Micronaut JSON schema

JSON schema support for Micronaut

Version: 2.2.0-SNAPSHOT

1 Introduction

JSON Schema is a human-readable format for exchanging data that also enables JSON data consistency, validity and interoperability.

Micronaut JSON Schema assists transforming schemas to beans and beans to schemas in your applications.

It also includes a configuration validator that can validate Micronaut configuration against JSON Schemas on the classpath.

2 Dependencies

In order to create JSON Schema from beans, add Micronaut JSON Schema processor to the annotation processor scope of your build configuration,

annotationProcessor("io.micronaut.jsonschema:micronaut-json-schema-processor")
<annotationProcessorPaths>
    <path>
        <groupId>io.micronaut.jsonschema</groupId>
        <artifactId>micronaut-json-schema-processor</artifactId>
    </path>
</annotationProcessorPaths>

and the Micronaut JSON Schema Annotations dependency to compile classpath:

implementation("io.micronaut.jsonschema:micronaut-json-schema-annotations")
<dependency>
    <groupId>io.micronaut.jsonschema</groupId>
    <artifactId>micronaut-json-schema-annotations</artifactId>
</dependency>

In order to create beans from JSON Schema, add Micronaut JSON Schema generator dependency to compile classpath:

implementation("io.micronaut.jsonschema:micronaut-json-schema-generator")
<dependency>
    <groupId>io.micronaut.jsonschema</groupId>
    <artifactId>micronaut-json-schema-generator</artifactId>
</dependency>

The Generator module can also be directly used with the Micronaut’s Gradle and Maven Plugins.

3 Quick Start

Annotate a bean with JsonSchema to trigger the creation of a schema for it during build time:

package io.micronaut.jsonschema.test;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import io.micronaut.jsonschema.JsonSchema;
import io.micronaut.serde.annotation.Serdeable;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.PositiveOrZero;

/**
 * A llama. (4)
 *
 * @param name The name
 * @param age The age
 */
@JsonSchema // (1)
@Serdeable // (2)
public record Llama(
    @NotBlank // (3)
    @JsonInclude(Include.NON_NULL)
    String name,
    @PositiveOrZero // (3)
    Integer age
) {
}
package io.micronaut.jsonschema.test

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonInclude.Include
import io.micronaut.jsonschema.JsonSchema
import io.micronaut.serde.annotation.Serdeable
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.PositiveOrZero

/**
 * A llama. (4)
 *
 * @param name The name
 * @param age The age
 */
@JsonSchema // (1)
@Serdeable // (2)
class Llama(
        @field:JsonInclude(Include.NON_NULL)
        @field:NotBlank
        val name: String,
        @field:PositiveOrZero
        val age: Int? // (3)
)
package io.micronaut.jsonschema.test

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.annotation.JsonInclude.Include
import io.micronaut.jsonschema.JsonSchema
import io.micronaut.serde.annotation.Serdeable
import jakarta.validation.constraints.NotBlank
import jakarta.validation.constraints.PositiveOrZero

/**
 * A llama. (4)
 */
@JsonSchema // (1)
@Serdeable // (2)
class Llama {
    /**
     * The name.
     */
    @NotBlank // (3)
    @JsonInclude(Include.NON_NULL)
    String name

    /**
     * The age.
     */
    @PositiveOrZero // (3)
    Integer age
}
1 Add the JsonSchema annotation.
2 (Optional) To use Micronaut Serialization as the serialization solution for your application refer to the Micronaut Serialization documentation and add Serdeable annotation to the bean.
3 Add additional required annotations to your bean. See supported annotations in the following sections.
4 The JavaDoc will be added as schema description.

The following file will be created on the classpath: META-INF/schemas/llama.schema.json.

{
  "$schema":"https://json-schema.org/draft/2020-12/schema",
  "$id":"http://localhost:8080/schemas/llama.schema.json",
  "title":"Llama",
  "description":"A llama. <4>",
  "type":"object",
  "properties":{
    "age":{
      "description":"The age",
      "type":"integer",
      "minimum":0
    },
    "name":{
      "description":"The name",
      "type":"string",
      "minLength":1
    }
  },
  "required":["age"]
}

It can be used in your application and will be included in the jar file.

4 Creating Schema From Beans

This section explains the processes involved for creating JSON schema from Beans.

4.1 JSON Schema Configuration

The generation can be configured globally with annotation processor options:

// For Java
tasks.withType(JavaCompile).configureEach {
    options.compilerArgs.add("-Amicronaut.jsonschema.baseUri=https://example.com/schemas") // (1)
}
// For Groovy
tasks.withType(GroovyCompile).configureEach {
    options.compilerArgs.add("-Amicronaut.jsonschema.baseUri=https://example.com/schemas") // (1)
}
// For KSP
ksp {
    arg("micronaut.jsonschema.baseUri", "https://example.com/schemas") // (1)
}
// For Kapt
kapt {
    arguments {
        arg("micronaut.jsonschema.baseUri", "https://example.com/schemas") // (1)
    }
}
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <compilerArgs>
                    <arg>-Amicronaut.jsonschema.baseUri=https://example.com/schemas</arg> <!-- (1) -->
                </compilerArgs>
            </configuration>
        </plugin>
    </plugins>
</build>
1 Set the base URL for all the schemas. It will be prepended to all relative schema URLs.

With the previous configuration, the following file will be created on the classpath: META-INF/schemas/llama.schema.json.

{
  "$schema":"https://json-schema.org/draft/2020-12/schema",
  "$id":"https://example.com/schemas/llama.schema.json",
  "title":"Llama",
  "description":"A llama. <4>",
  "type":"object",
  "properties":{
    "age":{
      "description":"The age",
      "type":"integer",
      "minimum":0
    },
    "name":{
      "description":"The name",
      "type":"string",
      "minLength":1
    }
  }
}

All the supported options are:

Option Description

micronaut.jsonschema.baseUri

Set the base URL for all the schemas. It will be prepended to all relative schema URLs.

micronaut.jsonschema.outputLocation

The location where JSON schemas will be generated inside the build META-INF/ directory.

micronaut.jsonschema.binaryAsArray

Whether to encode byte array as a JSON array. The default and preferred behavior is to encode it as a Base64-encoded string.

micronaut.jsonschema.draft

Specify the JSON Schema draft versions. Currently only DRAFT_2020_12 value is supported.

micronaut.jsonschema.strictMode

Whether to generate schemas in strict mode. In strict mode unresolved properties in JSON will cause an error. All the properties that are not annotated as nullable must be non-null.

4.2 JSON Schema Annotation Members

Schema generation can be configured with properties of the JsonSchema annotation, for example:

@JsonSchema(
    title = "RedWingedBlackbird", // (1)
    description = "A species of blackbird with red wings",
    uri = "/red-winged-blackbird" // (2)
)
@Serdeable
public record RWBlackbird(
    String name,
    Double wingSpan
) {
}
@JsonSchema(
    title = "RedWingedBlackbird", // (1)
    description = "A species of blackbird with red wings",
    uri = "/red-winged-blackbird" // (2)
)
@Serdeable
class RWBlackbird (
        val name: String,
        val wingSpan: Double?
)
@JsonSchema(
    title = "RedWingedBlackbird", // (1)
    description = "A species of blackbird with red wings",
    uri = "/red-winged-blackbird" // (2)
)
@Serdeable
class RWBlackbird {
    /**
     * The name.
     */
    String name

    /**
     * The wingspan.
     */
    Double wingSpan
}
1 Configure the title and description of the generated JSON Schema.
2 Set the relative or absolute URL. This will affect the file name as well as the id by which this schema can be referenced.

For the previous class, the following file will be created on the classpath: META-INF/schemas/red-winged-blackbird.schema.json.

{
  "$schema":"https://json-schema.org/draft/2020-12/schema",
  "$id":"http://localhost:8080/schemas/red-winged-blackbird.schema.json",
  "title":"RedWingedBlackbird",
  "description":"A species of blackbird with red wings",
  "type":"object",
  "properties":{
    "name":{
      "description":"The name",
      "type":"string"
    },
    "wingSpan":{
      "description":"The wing span of the bird",
      "type":"number"
    }
  }
}

4.3 Serving JSON Schemas

To expose the generated JSON Schema output from your running application, add static resources configuration.

micronaut.router.static-resources.jsonschema.paths=classpath:META-INF/schemas
micronaut.router.static-resources.jsonschema.mapping=/schemas/**
micronaut.jsonschema.validation.baseUri=https://example.com/schemas
1 The schemas are exposed on the /schemas path, which can be customized for your specific needs.
2 The schemas are be read from the META-INF/schemas classpath folder.

4.4 Loading JSON Schemas

If you want to load the generated JSON Schema, you can inject a bean of type JsonSchemaClassPathResourceLoader. You need the following dependency:

implementation("io.micronaut.jsonschema:micronaut-json-schema-utils")
<dependency>
    <groupId>io.micronaut.jsonschema</groupId>
    <artifactId>micronaut-json-schema-utils</artifactId>
</dependency>

4.5 JSON Schema Validation

If you want to validate a JSON file against your generated JSON Schema, you can inject a bean of type JsonSchemaValidator. You need the following dependency:

implementation("io.micronaut.jsonschema:micronaut-json-schema-validation")
<dependency>
    <groupId>io.micronaut.jsonschema</groupId>
    <artifactId>micronaut-json-schema-validation</artifactId>
</dependency>

4.6 Supported Information Sources

Information for JSON schema is aggregated from multiple sources.

4.6.1 JavaDoc

JavaDoc on types and properties will be added to the description properties of schemas. This includes class, property descriptions and record parameter descriptions.

4.6.2 Validation Annotations

The following jakarta.validation.constraints annotations are supported:

Validation Annotations Supported Comment

AssertFalse

AssertTrue

DecimalMin

DecimalMax

Email

Max

Min

Negative

NegativeOrZero

NotBlank

NotEmpty

NotNull

Null

Pattern

Positive

PositiveOrZero

Size

Digits

Future

JSON schema does not define fields for validating date-time formats

FutureOrPresent

JSON schema does not define fields for validating date-time formats

Past

JSON schema does not define fields for validating date-time formats

PastOrPresent

JSON schema does not define fields for validating date-time formats

By default, properties are not nullable. jakarta.annotations.Nullable can be added to make them nullable. Note, that validation might not correspond to actual bean values, as by default null values are completely omitted during JSON serialization.

Custom validators cannot be supported, as this information is implementation-specific and not available during build time.

4.6.3 Jackson Annotations

The following com.fasterxml.jackson.annotation annotations are supported:

Jackson Annotations Supported Comment

JacksonInject

The annotation has no effect

JsonAnyGetter

JsonAnySetter

JsonClassDescription

JsonGetter

JsonIgnore

JsonIgnoreProperties

JsonIgnoreType

JsonInclude

JsonIncludeProperties

JsonMerge

The annotation has no effect

JsonProperty

JsonPropertyDescription

JsonSetter

JsonSubTypes

JsonTypeInfo

include values WRAPPER_ARRAY and EXTERNAL_PROPERTY are not supported

JsonTypeName

JsonUnwrapped

JsonPropertyOrder

The annotation has no effect

JsonAlias

JsonAutoDetect

JsonBackReference

JsonCreator

JsonEnumDefaultValue

JsonFilter

Cannot be supported*

JsonFormat

JsonIdentityInfo

JsonIdentityReference

JsonKey

JsonManagedReference

JsonRawValue

JsonRootName

JsonTypeId

JsonValue

JsonView

*Custom serializers and deserializers cannot be supported, as this information is implementation-specific and not available during build time. This also applies to some other features, like the JsonFilter annotation which allows defining custom filters.

5 Generating Beans from Schema

This section explains the processes involved for generating source code of beans from JSON schema.

In addition to generating sources from schema files, URLs, and runtime inputs, this project also includes opt-in Gradle and Maven support for pluggable schema discovery, with built-in Oracle providers for SQL domains and JSON Relational Duality Views. See the record generation from discovered schemas section for the overall pipeline.

5.1 Build-time Generation Configuration

All the supported configuration options are:

Option Description

language

Set the language of generation for the beans. This is an optional field. Defaults to JAVA. Micronaut SourceGen module is used for generation and thus available generation languages are given here.

classpath

Classpath is taken from the gradle configurations for the task. This is a mandatory field.

jsonURL

Loads a valid JSON schema from the given input URL. This is an optional field.

jsonFile

Loads a valid JSON schema from the given input File. This is an optional field.

inputDirectory

Loads all valid JSON schemas from the given input folder. This is an optional field.

outputDirectory

The path where source files are generated. This is a mandatory field.

packageName

The package name of the generated source files. This is an optional field.

outputFileName

The file name of the generated source file. This field is taken into account when there is only one bean generated. If not specified, schema’s title or schema file’s name is considered for the generated file. This is an optional field.

acceptedUrlPatterns

A String list that has allowed URL patterns that are accepted for the references inside the schema. This is an optional field. The default pattern is "^https://./..json".

1 It is important to note that all three input options (jsonURL, jsonFile, and inputDirectory) are optional but at least one must be stated. In case multiple inputs are given, only one will be accepted following the order: inputDirectory, jsonURL, and jsonFile.

5.2 Run-time Generation Configuration

The source generation from JSON schema can also be used during run-time with the generator package. The following code snippet shows how SourceGenerator object can be used to generate beans of your desired language from JSON schema.

// create a generator with your chosen language
var javaGenerator = new SourceGenerator("JAVA");

// Optional: can configure accepted URL references
UrlLoader.setAllowedUrlPatterns(List.of("^https://.*/.*.schema.json$"));
UrlLoader.addAllowedUrlPattern("^http://localhost:.*");

// Optional: set up input file name
String schemaFileName = "example.schema.json";
SourceGenerator.setInputFileName(schemaFileName);

Path outputPath = Paths.get("output"); // Define the base output path
String packageName = "com.example.temp"; // Example package name
SourceGeneratorConfig config = new SourceGeneratorConfigBuilder()
                                    .withOutputFolder(outputPath)
                                    .withOutputPackageName(packageName)
                                    .withJsonUrl("https://www.jsonschemastore.org/example/temp.schema.json")
                                    .build();

javaGenerator.generate(config);
1 Setting up allowedUrlPatterns would provide a check for all URL references inside the schema.
2 The input file name does not need to be specified. It is usually extracted from the given URL, file, or folder. This name might be used while deciding on the same of the top level schema if there is no title available in the schema.
3 Calling the SourceGenerator's generate(SourceGeneratorConfig config) function will generate beans inside the given config’s output location. The function will return the generated File object of the top level schema when there is a single input schema. Otherwise (a folder of schemas), the function would return null regardless of generation completion status.

The SourceGeneratorConfigBuilder methods are similar to that of `BeanGeneratorTask’s configuration explained in the previous section. There are explained below:

Option Description

withInputStream(InputStream inputStream)

Loads a valid JSON schema from given an InputStream.

withJsonUrl(String jsonUrl)

Loads a valid JSON schema from the given input URL.

withJsonFile(File jsonFile)

Loads a valid JSON schema from the given input File.

withInputFolder(Path inputFolder)

Loads all valid JSON schemas from the given input folder.

withOutputFolder(Path outputFolder)

The path where source files are generated.

withOutputPackageName(String outputPackageName)

The package name of the generated source files.

withOutputFileName(String outputFileName)

The file name of the generated source file. This field is taken into account when there is only one bean generated. If not specified, schema’s title or schema file’s name is considered for the generated file.

1 It is important to note that one of input options (inputStream, jsonURL, jsonFile, and inputFile) must be stated. In case multiple inputs are given, only one will be accepted following the order: inputFolder, inputStream, jsonURL, and jsonFile.

5.3 Record Generation From Discovered Schemas

The JSON Schema records pipeline discovers JSON Schema documents at build time and generates Java or Kotlin source files from them. It is useful when schemas are not stored as project files, but are owned by another source of truth such as database metadata or another schema registry.

The pipeline has four main steps:

  • resolve configured discovery sources

  • discover JSON Schema documents through provider implementations

  • write the discovered schemas and manifest to a cache directory

  • generate Java records/classes or Kotlin data classes into the configured output directory

Generation is opt-in. The Gradle task and Maven goal are not bound to normal compilation by default, but when they run they add the generated source directory to the current build so generated types can be compiled in the same invocation. When Gradle’s org.jetbrains.kotlin.jvm plugin is applied and language = "KOTLIN", the generated directory is also registered with the main Kotlin source set. For Maven, the goal’s skip option defaults to true; configure <skip>false</skip> or pass -DjsonSchemaRecords.skip=false when generation should run.

Source Configuration

A build configures one or more discovery sources. Each source has a stable name, a provider id, and provider-specific options:

jsonSchemaRecords {
    targetPackage = "example.generated"
    language = "JAVA"
    sources = [
        [
            name: "domains",
            provider: "oracle-domains",
            options: [
                owner: "APP",
                include: "CUSTOMER_JSON"
            ]
        ]
    ]
}

name is used in diagnostics, cache layout, and manifest entries. provider selects the discovery provider. options are interpreted only by the selected provider.

Built-in provider ids include:

Provider id Description

oracle-domains

Discovers Oracle SQL domains that declare JSON validation rules.

oracle-duality-views

Discovers Oracle JSON Relational Duality Views.

See the Oracle discovery guide for provider-specific JDBC settings, Oracle owner scoping, and supported Oracle options.

Provider SPI

Discovery providers implement io.micronaut.jsonschema.generator.discovery.SchemaDiscoveryProvider. The provider exposes a stable id and returns discovered schema entries:

public interface SchemaDiscoveryProvider {

    String providerId();

    DiscoveryResult discover(SchemaDiscoveryContext context,
                             SourceSpec source) throws Exception;
}

Built-in providers are resolved by their known provider ids. Custom providers are loaded from the plugin/provider classpath with Java ServiceLoader. For custom providers, the configured provider value must match SchemaDiscoveryProvider.providerId().

Gradle custom providers are added to the jsonSchemaRecordsProviders configuration. Maven custom providers are added as plugin dependencies. The provider jar must include:

META-INF/services/io.micronaut.jsonschema.generator.discovery.SchemaDiscoveryProvider

That service file contains the provider implementation class name.

Generated Types

The pipeline delegates source generation to the existing JSON Schema generator and keeps its behavior where possible. The records profile applies a few additional rules where generated record/class semantics need to be stricter than the default generator. In particular, optional scalar properties are boxed, required controls property presence, and JSON Schema nullability controls value nullability. Property-level oneOf or anyOf with exactly one null branch and one concrete branch is treated as nullable-equivalent by the records profile, while broader oneOf and anyOf shapes still fall back to Object with diagnostics. At a discovered schema root, oneOf and anyOf are delegated to the existing polymorphic generation path. Nested enum type names are derived using the generated type-name sanitizer. For ordinary property names this matches the default generator, but unusual property names that are legal Java members and awkward Java type names can produce a cleaner nested enum type name than the default generator.

language selects the generated source language. Supported values are JAVA (the default) and KOTLIN.

For Java, the languageLevel option controls whether records can be emitted:

  • languageLevel >= 16: records are preferred when the schema shape can be represented as a valid record.

  • languageLevel < 16: classes are generated.

  • If a schema shape cannot be emitted as a valid record, the generator may emit a class.

For Kotlin, record-capable schemas are emitted as Kotlin data class declarations. languageLevel does not affect Kotlin output; configure the Kotlin compiler’s language version in the consuming build when required.

Generated files are written under outputDir. The configured targetPackage is used as the package for generated top-level types.

Cache And Manifest

Discovered JSON Schema documents are written under schemaCacheDir. The same directory also contains manifest.json, which records the effective generation inputs and outputs.

The manifest includes:

  • generator identity and timestamp

  • sanitized source metadata

  • effective parameters

  • discovered schema files

  • generated Java files

  • warnings and skipped inputs

Secrets must not be written to the manifest. Built-in Oracle providers sanitize JDBC metadata before it is persisted.

Error Handling

By default, generation fails when a configured source is unavailable, no inputs are discovered, a schema cannot be retrieved, or a generated Java name collision is detected.

Two options control how much work continues after errors:

Option Behavior

failOnMissingSource

Controls source-level discovery failures such as unavailable sources or no selected inputs.

skipOnError

Allows individual discovered inputs to be skipped when retrieval or generation fails.

Warnings and skipped inputs are written to manifest.json and logged with stable machine-readable codes.

Determinism

The pipeline uses stable ordering for pipeline-owned outputs and diagnostics, including discovered input processing, schema cache entries, manifest entries, generated file planning, warnings, skipped entries, and collision diagnostics.

This does not require sorting Java members, record components, JSON Schema properties, or $defs when doing so would change the existing JSON Schema-to-Java generator’s emitted API.

Limitations

The first version focuses on build-time source generation from configured providers. Remote $ref fetching, arbitrary JSON Pointer resolution beyond supported local references, and provider-specific credential mechanisms beyond the documented provider options are outside the first version.

Provider-specific limitations are documented by each provider guide.

5.4 Oracle Discovery and Plugins

Micronaut JSON Schema can also discover JSON Schema definitions directly from Oracle metadata and generate Java records from the discovered schemas.

The current Oracle discovery pipeline supports:

  • Oracle SQL domains that declare JSON validation rules

  • Oracle JSON Relational Duality Views

This Oracle flow is available through the generic jsonSchemaRecords Gradle and Maven plugin integration included in this project.

Built-in Oracle discovery providers are configured by provider id:

  • oracle-domains

  • oracle-duality-views

Each configured source declares:

  • name

  • provider

  • provider-specific options

Gradle

Apply the plugin and configure the target package plus one or more discovery sources:

plugins {
    id "io.micronaut.jsonschema.records"
}

jsonSchemaRecords {
    providers {
        oracle {
            jdbcUrl = project.providers.environmentVariable("DB_URL")
            username = project.providers.environmentVariable("DB_USER")
            password = project.providers.environmentVariable("DB_PASSWORD")
        }
    }
    targetPackage = "example.oracle.generated"
    sources = [
        [
            name: "domains",
            provider: "oracle-domains",
            options: [
                owner: "APP",
                include: "APP_JSON"
            ]
        ],
        [
            name: "views",
            provider: "oracle-duality-views",
            options: [
                owner: "APP",
                include: "APP_VIEW"
            ]
        ]
    ]
}

If the Oracle JDBC driver is not already visible to the task, provide it through jdbcClasspath.

configurations {
    jsonSchemaRecordsJdbc
}

dependencies {
    jsonSchemaRecordsJdbc "com.oracle.database.jdbc:ojdbc11:<version>"
}

jsonSchemaRecords {
    jdbcClasspath.from(configurations.jsonSchemaRecordsJdbc)
}

Custom discovery providers can be added through the dedicated jsonSchemaRecordsProviders configuration:

dependencies {
    jsonSchemaRecordsProviders project(":oracle-schema-providers")
}

jsonSchemaRecords {
    sources = [
        [
            name: "legacy",
            provider: "legacy-oracle",
            options: [
                tablePattern: "LEGACY_%"
            ]
        ]
    ]
}

Custom providers are selected by provider, which must match the provider id returned by the provider implementation. The provider jar must be present on jsonSchemaRecordsProviders, implement io.micronaut.jsonschema.generator.discovery.SchemaDiscoveryProvider, and register the implementation with Java ServiceLoader under META-INF/services/io.micronaut.jsonschema.generator.discovery.SchemaDiscoveryProvider.

The built-in providers currently support these source options:

Provider id Supported options

oracle-domains

owner, include, exclude

oracle-duality-views

owner, include, exclude

For the built-in providers, owner, include, and exclude are interpreted as unquoted Oracle identifiers and normalized to uppercase before dictionary filtering, session-user comparison, and discovery/cache file naming. Quoted or mixed-case Oracle identifiers are out of scope for the first version.

Generated Java temporal types are based on standard JSON Schema keywords first. For example, a schema property with "type": "string" and "format": "date-time" maps to java.time.ZonedDateTime. When a discovered Oracle schema has no standard format, the records profile also uses Oracle extendedType metadata as a type-mapping hint:

Oracle extendedType Java type

date, timestamp

java.time.LocalDateTime

timestampTz

java.time.ZonedDateTime

dsInterval

java.time.Duration

ymInterval

java.time.Period

double

double / java.lang.Double

float

float / java.lang.Float

binary

byte[]

When owner is configured, the built-in providers first try ALL_ and DBA_ dictionary views with an OWNER filter. If those cross-schema views are not queryable, the providers fall back to USER_ dictionary views only when the configured owner matches the Oracle session user. That fallback emits OWNER_SCOPE_FALLBACK; otherwise the source is unavailable with PRIVILEGE_DENIED.

Gradle credentials

The Gradle plugin can resolve connection settings from explicit extension values, Gradle properties, or environment variables.

Value Supported names

JDBC URL

providers.oracle.jdbcUrl, jsonSchemaRecords.jdbcUrl, DB_URL, JSON_SCHEMA_RECORDS_JDBC_URL

Username

providers.oracle.username, jsonSchemaRecords.username, DB_USER, JSON_SCHEMA_RECORDS_USERNAME

Password

providers.oracle.password, jsonSchemaRecords.password, DB_PASSWORD, JSON_SCHEMA_RECORDS_PASSWORD

This lets projects keep secrets outside build.gradle, for example in ~/.gradle/gradle.properties:

jsonSchemaRecords.jdbcUrl=jdbc:oracle:thin:@localhost:1521/FREEPDB1
jsonSchemaRecords.username=app
jsonSchemaRecords.password=secret

The same values can be supplied for a single invocation with Gradle project properties:

./gradlew generateFromJsonSchemaSources \
  -PjsonSchemaRecords.jdbcUrl=jdbc:oracle:thin:@localhost:1521/FREEPDB1 \
  -PjsonSchemaRecords.username=app \
  -PjsonSchemaRecords.password=secret

generateFromJsonSchemaSources writes Java source files only. To generate and compile the discovered types in the same Gradle invocation, request both tasks:

./gradlew generateFromJsonSchemaSources compileJava \
  -PjsonSchemaRecords.jdbcUrl=jdbc:oracle:thin:@localhost:1521/FREEPDB1 \
  -PjsonSchemaRecords.username=app \
  -PjsonSchemaRecords.password=secret

Maven

The Maven plugin can be configured in the build like any other mojo: The goal’s skip option defaults to true, so set <skip>false</skip> in plugin configuration or pass -DjsonSchemaRecords.skip=false when generation should run.

<plugin>
  <groupId>io.micronaut.jsonschema</groupId>
  <artifactId>micronaut-json-schema-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>generate-from-json-schema-sources</goal>
      </goals>
    </execution>
  </executions>
  <configuration>
    <skip>false</skip>
    <providers>
      <oracle>
        <jdbcUrl>${env.DB_URL}</jdbcUrl>
        <username>${env.DB_USER}</username>
        <password>${env.DB_PASSWORD}</password>
      </oracle>
    </providers>
    <targetPackage>example.oracle.generated</targetPackage>
    <sources>
      <source>
        <name>domains</name>
        <provider>oracle-domains</provider>
        <options>
          <owner>APP</owner>
          <include>APP_JSON</include>
        </options>
      </source>
      <source>
        <name>views</name>
        <provider>oracle-duality-views</provider>
        <options>
          <owner>APP</owner>
          <include>APP_VIEW</include>
        </options>
      </source>
    </sources>
  </configuration>
</plugin>

Custom discovery providers are loaded from the Maven plugin classpath, so add them as plugin dependencies:

<plugin>
  <groupId>io.micronaut.jsonschema</groupId>
  <artifactId>micronaut-json-schema-maven-plugin</artifactId>
  <dependencies>
    <dependency>
      <groupId>example.oracle</groupId>
      <artifactId>oracle-schema-providers</artifactId>
      <version>1.0.0</version>
    </dependency>
  </dependencies>
  <configuration>
    <sources>
      <source>
        <name>legacy</name>
        <provider>legacy-oracle</provider>
        <options>
          <tablePattern>LEGACY_%</tablePattern>
        </options>
      </source>
    </sources>
  </configuration>
</plugin>

As with Gradle, the configured provider must match a SchemaDiscoveryProvider implementation registered through Java ServiceLoader on the Maven plugin classpath.

Troubleshooting Custom Providers

If a custom provider is not resolved at runtime, check these points first:

  • The provider jar is on the plugin classpath.

  • Gradle uses jsonSchemaRecordsProviders.

  • Maven uses plugin <dependencies>, not regular project dependencies.

  • The provider implementation has a public no-argument constructor.

  • The provider and plugin use compatible micronaut-json-schema versions.

  • Any transitive libraries required by the provider are also visible on the same plugin classpath.

Maven credentials

The Maven plugin supports provider-family configuration, direct properties, environment variables, and Maven settings.xml server lookup.

You can pass connection settings directly on the command line:

mvn generate-sources \
  -DjsonSchemaRecords.skip=false \
  -DjsonSchemaRecords.jdbcUrl=jdbc:oracle:thin:@localhost:1521/FREEPDB1 \
  -DjsonSchemaRecords.username=app \
  -DjsonSchemaRecords.password=secret \
  -DjsonSchemaRecords.targetPackage=example.oracle.generated

For better secret handling, configure a Maven server and pass only serverId:

<settings>
  <servers>
    <server>
      <id>jsonschema</id>
      <username>app</username>
      <password>secret</password>
    </server>
  </servers>
</settings>
mvn generate-sources \
  -DjsonSchemaRecords.skip=false \
  -DjsonSchemaRecords.jdbcUrl=jdbc:oracle:thin:@localhost:1521/FREEPDB1 \
  -DjsonSchemaRecords.serverId=jsonschema \
  -DjsonSchemaRecords.targetPackage=example.oracle.generated

Credential resolution order is:

  • Explicit plugin configuration or -DjsonSchemaRecords.username / -DjsonSchemaRecords.password

  • providers.oracle

  • serverId lookup from Maven settings.xml

  • DB_URL, DB_USER, DB_PASSWORD

  • JDBC-backed providers fail if required connection settings are still missing

5.5 Supported JSON Schema Keywords and Limitations

The following JSON schema keywords are processed by the generation:

JSON Schema keyword Supported Notes or Limitations

$id

$schema

type

Accepted type keywords are: array, boolean, null, number, integer, object, and string. Type keyword can accept an array of type values. However, in case of more than one non-null type, the generated type will be a java.lang.Object or an equivalent in the language of choice.

title

description

properties

$comment

$ref

Self, local, remote, and url references are accepted. However, for remote references, the generation needs to be given the top local input directory during configuration.

$dynamicRef

$defs

The definitions keyword is also accepted.

format

Teh closest existing class is decided as the type of object when the format is given. For example, for a ""type": "string", "format": "date"" schema, a LocalDate object is created in Java. Supported format keywords are: date, date-time, time, duration, ipv4, ipv6, uuid, uri, iri, and json-pointer.

const

enum

items

oneOf

Only a top level oneOf relation is processed as an inheritance relation. In case there are primitive types included, they are discarded. A oneOf keyword given inside properties or definitions are discarded. The type of any discarded relation will be java.lang.Object or an equivalent in the language of choice.

allOf

anyOf

The strategy to choose from an anyOf keyword: if empty, return null; if single schema, return that schema; if there are two schema but one has type "NULL", return the non-null schema; if all schemas has the same type, merge all schemas and return; else return empty Object schema.

discriminator, propertyName, mapping

These keywords are not actually part of JSON schema, but is commonly used (with oneOf). It is defined as part of a similar specification.

additionalProperties

patternProperties

unevaluatedProperties

defaultValue, default

Even though default values are generally discarded, they are supported in enum types.

deprecated

readOnly

writeOnly

examples

not

if-then-else

The source code generation decides which object type to use for representing the schema depending on the schema’s values. An interface is created to represent a oneOf relation. An enum class is created when the enum keyword is used. A class object is created when it belongs to an inheritance, has too many properties for a record (255+), has const properties, or has additional properties. In the remaining cases of an object with properties, a record is created.

The validation conditions are kept on the generated beans through jakarta.validation.constraints annotations. Below is a list of JSON schema validation keywords that are supported and their corresponding annotations:

Validation keywords Supported Annotation equivalent Notes

required

NotNull

dependentRequired

nullable

jakarta.annotation.Nullable

multipleOf

minimum

Min or DecimalMin

Depends on whether the type is an integer or a floating point number.

maximum

Max or DecimalMax

Depends on whether the type is an integer or a floating point number.

exclusiveMinimum

Min or DecimalMin

Depends on whether the type is an integer or a floating point number.

exclusiveMaximum

Max or DecimalMax

Depends on whether the type is an integer or a floating point number.

maxLength

Size

minLength

Size

maxItems

Size

minItems

Size

uniqueItems

When true, generates a Set object instead of the default List object.

maxContains

Size

minContains

Size

contains

This keyword is processed only when the items keyword for an array is not found. Unlike the JSON schema description, the contains keyword will be validated against all items in the array.

pattern

Pattern

Supported fully with strings and has limited support with numerical types. Pattern information on numerical types can help decide on whether the value is positive, zero, and/or negative.

email

Email

format's email keyword.

prefixItems

propertyNames

minProperties

maxProperties

5.6 Example Output of Generation

The following file is an example JSON schema describing an Animal interface which is implemented by Dog, Cat, Fish and Human objects.

{
  "$schema":"https://json-schema.org/draft/2020-12/schema",
  "$id":"https://example.com/schemas/llama.schema.json",
  "title":"Animal",
  "description":"An animal.",
  "type":["object"],
  "properties":{
    "id": {
      "description": "Unique id for the animal.",
      "$ref": "#/definitions/id"
    },
    "birthdate":{
      "description":"The birthdate",
      "$ref": "#/definitions/date"
    },
    "name":{
      "description":"The name",
      "type":"string",
      "minLength":1
    }
  },
  "discriminator": {
    "propertyName": "resourceType",
    "mapping": {
      "Cat": "#/definitions/Cat",
      "Dog": "#/definitions/Dog",
      "Fish": "#/definitions/Fish",
      "Human": "#/oneOf/Human"
    }
  },
  "oneOf": [{
    "$ref": "#/definitions/Cat"
  },{
    "$ref": "#/definitions/Dog"
  },{
    "$ref": "#/definitions/Fish"
  }, {
    "title": "Human",
    "type": "object",
    "properties": {
      "resourceType": {
        "const": "Human"
      },
      "firstName": {
        "type": "string"
      },
      "lastName": {
        "type": "string"
      },
      "sport": {
        "type": "string"
      }
    }
  }],
  "$defs": {
    "id": {
      "pattern": "^[A-Za-z0-9\\-\\.]{1,64}$",
      "type": "string",
      "description": "Any combination of letters, numerals, \"-\" and \".\", with a length limit of 64 characters.  (This might be an integer, an unprefixed OID, UUID or any other identifier pattern that meets these constraints.)  Ids are case-insensitive."
    },
    "date": {
      "pattern": "^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1]))?)?$",
      "type": "string",
      "description": "A date or partial date (e.g. just year or year + month). There is no UTC offset. The format is a union of the schema types gYear, gYearMonth and date.  Dates SHALL be valid dates."
    },
    "boolean": {
      "pattern": "^true|false$",
      "type": "boolean",
      "description": "Value of \"true\" or \"false\""
    },
    "Cat": {
      "description": "The definition of a cat.",
      "properties": {
        "resourceType": {
          "description": "This is a Cat resource.",
          "const": "Cat"
        },
        "hasMate": {
          "description": "True when the cat has found their mate.",
          "$ref": "#/definitions/boolean"
        }
      },
      "type": ["object"],
      "additionalProperties": false
    },
    "Dog": {
      "description": "The definition of a dog.",
      "properties": {
        "resourceType": {
          "description": "This is a Dog resource.",
          "const": "Dog"
        },
        "hasMate": {
          "description": "True when the dog has found their mate.",
          "const": true
        },
        "nickname" : {
          "description": "A nickname of a good doggo.",
          "type": "string"
        },
        "enemies" : {
          "description": "A list of the dog's cat enemies.",
          "type": "array",
          "items": {
            "$ref": "#/definitions/Cat"
          }
        }
      },
      "type": "object",
      "additionalProperties": {"type": "string"}
    },
    "Fish": {
      "description": "The definition of a fish.",
      "properties": {
        "resourceType": {
          "description": "This is a Fish resource.",
          "const": "Fish"
        },
        "friends" : {
          "description": "A list of the fish's aquarium friends.",
          "type": "array",
          "items": {
            "$ref": "#"
          }
        }
      },
      "type": "object",
      "additionalProperties": true
    }
  }
}

The following example shows how the JsonMapper can map the JSON data to the best fitting/correct class in the inheritance relation even though only the interface is given to the function.

@Test
public void mapCat() throws JacksonException {
    var animal = jsonMapper.readValue("""
        {
          "id": "0x",
          "birthdate": "2000-01-01",
          "name": "Micronaut",
          "resourceType": "Cat",
          "hasMate": true
        }
        """, Animal.class);
    assertEquals(Cat.class, animal.getClass());
    Cat cat = (Cat) animal;

    assertEquals("0x", cat.getId());
    assertEquals("2000-01-01", cat.getBirthdate());
    assertEquals("Micronaut", cat.getName());
    assertEquals(true, cat.getHasMate());
    assertEquals("Cat", cat.resourceType);
}

The following example showcases that the generated beans can be re-serialized into the same JSON Schema.

@Test
void testSerializeGeneratedAdditionalProperty(ObjectMapper objectMapper) throws IOException {
    String inputData = """
        {
          "resourceType": "Dog",
          "id": "0x",
          "birthdate": "2000-01-01",
          "name": "Micronaut",
          "nickname": "Goodie",
          "enemies": [
          {
              "resourceType": "Cat",
              "id": "1x",
              "birthdate": "2000-01-01",
              "name": "Pegasus",
              "hasMate": false
          }, {
              "resourceType": "Cat",
              "id": "2x",
              "birthdate": "2000-01-01",
              "name": "Micro-Pego",
              "hasMate": false
          }],
          "hasMate": true,
          "ownerName": "Owner"
        }
        """.replaceAll("\\s", "");
    var dog = jsonMapper.readValue(inputData, Dog.class);

    String result = objectMapper.writeValueAsString(dog);
    assertEquals(inputData, result);
}

6 Validating Configuration Against Schemas

The Micronaut JSON Schema configuration validator validates application configuration against JSON Schemas discovered on the classpath.

It is designed for:

  • CI checks (fail builds when invalid configuration is committed)

  • local troubleshooting (human-friendly HTML reports with file/line/snippet information)

  • validating Micronaut’s shipped configuration schemas as well as schemas generated from @ConfigurationProperties

Dependency

implementation("io.micronaut.jsonschema:micronaut-json-schema-configuration-validator")
<dependency>
    <groupId>io.micronaut.jsonschema</groupId>
    <artifactId>micronaut-json-schema-configuration-validator</artifactId>
</dependency>

You can use the ConfigurationErrors API to access to configuration validation errors.

How schemas are discovered

The validator loads schemas via JsonSchemaClassPathResourceLoader:

  • META-INF/micronaut-configuration-schemas/ (Micronaut-shipped configuration schemas)

  • generated configuration schemas on the classpath (when using the Micronaut JSON Schema annotation processor)

Schemas are grouped by the Micronaut metadata prefix (x-micronaut.prefix).

Placeholder resolution

Configuration is read from Micronaut’s Environment; placeholder values (for example ${some.other.property}) are validated after Micronaut resolves them.

Deprecated properties

If a schema property is marked as deprecated ("deprecated": true), the validator emits a WARNING when the property is present.

Unknown properties and suppressions

By default unknown properties are treated as errors (and some schemas also enforce this via additionalProperties: false).

Built-in suppression patterns silence known framework-managed properties such as micronaut.home, micronaut.processing, and micronaut.test-resources*.

You can downgrade matching errors to warnings by configuring your own suppression patterns (for example micronaut.http.*).

Reports

The CLI writes reports into the output directory:

  • configuration-errors.json

  • configuration-errors.html

If an error originates from a resolvable file (for example application.properties, application.yml, application.toml), the validator attempts to include:

  • origin location

  • 1-based line number

  • a small code snippet

The HTML report includes an expandable snippet preview with syntax highlighting. The JSON report includes only the line number.

Dependency injection validation

In addition to schema/property validation, the validator can also perform metadata-only dependency injection checks.

This catches wiring issues before application startup, including:

  • missing bean dependencies

  • circular dependencies

  • disabled candidate beans (with @Requires reasons)

  • ambiguous candidates that would fail with a non-unique bean error at runtime

  • unresolved dependencies of @Factory-produced beans

CLI usage

Enable DI validation by adding --validate-dependency-injection:

java -cp <full-classpath> io.micronaut.jsonschema.configuration.validator.cli.ConfigurationJsonSchemaValidatorCli \
  --classpath <full-classpath> \
  --environments test \
  --out build/reports/config-schema \
  --format both \
  --suppress-inject-errors com.example.LegacyBean,com.example.generated.* \
  --validate-dependency-injection

When enabled, console, JSON, and HTML outputs include a dedicated DI section (errors + dependency failure paths).

Use --suppress-inject-errors to suppress DI errors for specific bean classes or packages. Patterns support exact fully-qualified class names and wildcards (for example com.example.LegacyBean or com.example.generated.).

Use --dependency-injection-validation-strategy to control validation scope:

  • reachable (default): validates only reachable roots (@Context, controllers, startup listeners, and entry points)

  • application-beans: validates only application bean definitions generated in the current project (and ignores dependency JAR bean definitions)

  • all-beans: validates all bean definitions on the classpath (slowest option)

The JSON report (configuration-errors.json) adds a dependencyInjectionErrors array containing entries such as:

  • rootBean

  • bean

  • injectionPoint

  • details

  • disabledReason (when applicable)

  • failingPath

Runtime API and management integration

When micronaut-management is present and DI validation is enabled, the module also exposes DI results at runtime:

  • DependencyInjectionErrors API

  • management endpoint id injecterrors (property: micronaut.jsonschema.configuration.validator.injecterrors.endpoint.enabled)

  • health indicator id injecterrors (property: endpoints.health.injecterrors.enabled)

Example endpoint configuration:

micronaut.jsonschema.configuration.validator.dependency-injection.enabled=true
micronaut.jsonschema.configuration.validator.dependency-injection.validation-strategy=reachable
micronaut.jsonschema.configuration.validator.injecterrors.endpoint.enabled=true
endpoints.all.sensitive=false
endpoints.injecterrors.sensitive=false
endpoints.health.injecterrors.enabled=true
micronaut:
  jsonschema:
    configuration:
      validator:
        dependency-injection:
          enabled: true
          validation-strategy: reachable
        injecterrors:
          endpoint:
            enabled: true
endpoints:
  all:
    sensitive: false
  injecterrors:
    sensitive: false
  health:
    injecterrors:
      enabled: true
micronaut = {jsonschema = {configuration = {validator = {dependency-injection = {enabled = true, validation-strategy = "reachable"}, injecterrors = {endpoint = {enabled = true}}}}}}
endpoints = {all = {sensitive = false}, injecterrors = {sensitive = false}, health = {injecterrors = {enabled = true}}}
micronaut {
  jsonschema {
    configuration {
      validator {
        dependencyInjection {
          enabled = true
          validationStrategy = "reachable"
        }
        injecterrors {
          endpoint {
            enabled = true
          }
        }
      }
    }
  }
}
endpoints {
  all {
    sensitive = false
  }
  injecterrors {
    sensitive = false
  }
  health {
    injecterrors {
      enabled = true
    }
  }
}
{
  micronaut {
    jsonschema {
      configuration {
        validator {
          dependency-injection {
            enabled = true
            validation-strategy = "reachable"
          }
          injecterrors {
            endpoint {
              enabled = true
            }
          }
        }
      }
    }
  }
  endpoints {
    all {
      sensitive = false
    }
    injecterrors {
      sensitive = false
    }
    health {
      injecterrors {
        enabled = true
      }
    }
  }
}
{
  "micronaut": {
    "jsonschema": {
      "configuration": {
        "validator": {
          "dependency-injection": {
            "enabled": true,
            "validation-strategy": "reachable"
          },
          "injecterrors": {
            "endpoint": {
              "enabled": true
            }
          }
        }
      }
    }
  },
  "endpoints": {
    "all": {
      "sensitive": false
    },
    "injecterrors": {
      "sensitive": false
    },
    "health": {
      "injecterrors": {
        "enabled": true
      }
    }
  }
}

Runtime integration (optional)

In addition to the CLI, the configuration validator module also provides optional runtime integrations:

  • a runtime API to access current configuration validation errors

  • a health indicator (reports DOWN when configuration has errors)

  • a management endpoint that exposes the validation errors

These runtime integrations are enabled by default, but the health indicator and endpoint are only loaded when the application includes the optional micronaut-management dependency.

Invalid configuration often causes application startup failures (for example if required configuration is missing, or if a component fails during initialization due to invalid values). In those cases, the application may not start and the runtime beans (including the management endpoint and health indicator) will not be available.

Runtime API

The module exposes a bean of type ConfigurationErrors that returns a snapshot of the current validation errors:

    void logConfigurationErrors() {
        configurationErrors.getCurrentErrors().forEach(System.out::println);
    }
    fun logConfigurationErrors() {
        configurationErrors.currentErrors.forEach(::println)
    }
    void logConfigurationErrors() {
        configurationErrors.currentErrors.each { println(it) }
    }

By default, the first computed validation result is cached for the lifetime of the application context.

Configuration

All runtime configuration is under the micronaut.jsonschema.configuration.validator prefix:

🔗
Table 1. Configuration Properties for ConfigurationValidatorConfiguration
Property Type Description Default value

micronaut.jsonschema.configuration.validator.cache

boolean

Whether the validation result should be cached. Default value true

micronaut.jsonschema.configuration.validator.fail-on-not-present

boolean

Whether to fail when configuration contains keys not present in schema. Default value true

micronaut.jsonschema.configuration.validator.suppressions

java.util.List

Patterns used to suppress validation errors

micronaut.jsonschema.configuration.validator.dependency-injection-validation-strategy

DependencyInjectionValidationStrategy

The DI validation strategy. Default value {@code REACHABLE}

Management endpoint

To use the configuration errors management endpoint and health indicator, add:

implementation("io.micronaut:micronaut-management")
<dependency>
    <groupId>io.micronaut</groupId>
    <artifactId>micronaut-management</artifactId>
</dependency>

The endpoint can be enabled or disabled via the endpoints.configurationerrors.enabled property (default: true).

When enabled, the management endpoint is available under id configurationerrors and returns a JSON response containing an errors namespace.

Management endpoints are sensitive by default. For tests and local development you may want to disable sensitivity:
endpoints.all.sensitive=false
endpoints.configurationerrors.sensitive=false
endpoints.configurationerrors.enabled=true
endpoints:
  all:
    sensitive: false
  configurationerrors:
    sensitive: false
    enabled: true
endpoints = {all = {sensitive = false}, configurationerrors = {sensitive = false, enabled = true}}
endpoints {
  all {
    sensitive = false
  }
  configurationerrors {
    sensitive = false
    enabled = true
  }
}
{
  endpoints {
    all {
      sensitive = false
    }
    configurationerrors {
      sensitive = false
      enabled = true
    }
  }
}
{
  "endpoints": {
    "all": {
      "sensitive": false
    },
    "configurationerrors": {
      "sensitive": false,
      "enabled": true
    }
  }
}

Health indicator

🔗
Table 2. Configuration Properties for HealthConfiguration
Property Type Description Default value

endpoints.health.configurationerrors.enabled

boolean

Whether the configuration validation health indicator is enabled. Default value true

When enabled, the health indicator reports DOWN if any configuration validation errors are present. It also includes a bounded sample of the failing properties and messages in the response details.

Custom validation rules (ServiceLoader)

Some validation rules cannot be expressed as JSON Schema keywords alone, for example validating dependent configuration entries.

The configuration validator supports custom rules via the ConfigurationRule SPI. Implementations are discovered using ServiceLoader from the same classloader used to load configuration schemas.

Rule API

Rules receive a ConfigurationValidationContext that includes:

For @EachProperty schemas, the prefix is the fully qualified entry prefix (for example test.executors.alpha).

Example: dependent configuration

The following example requires datasources.default.url when jpa.default.properties is present:

    @Override
    public boolean supportsPrefix(String prefix) {
        return "jpa.default.properties".equals(prefix);
    }

    @Override
    public Set<ConfigurationError> validate(ConfigurationValidationContext context) {
        Set<ConfigurationError> errors = new LinkedHashSet<>();

        if (!context.environment().containsProperty("datasources.default.url")) {
            errors.add(ConfigurationError.builder(
                "datasources.default.url",
                "Required when jpa.default.properties is set"
            ).build());
        }

        return errors;
    }
    override fun supportsPrefix(prefix: String): Boolean = prefix == "jpa.default.properties"

    override fun validate(context: ConfigurationValidationContext): Set<ConfigurationError> {
        val errors = LinkedHashSet<ConfigurationError>()

        if (!context.environment.containsProperty("datasources.default.url")) {
            errors.add(
                ConfigurationError.builder(
                    "datasources.default.url",
                    "Required when jpa.default.properties is set"
                ).build()
            )
        }

        return errors
    }
    @Override
    boolean supportsPrefix(String prefix) {
        prefix == 'jpa.default.properties'
    }

    @Override
    Set<ConfigurationError> validate(ConfigurationValidationContext context) {
        Set<ConfigurationError> errors = new LinkedHashSet<>()

        if (!context.environment().containsProperty('datasources.default.url')) {
            errors.add(ConfigurationError.builder(
                    'datasources.default.url',
                    'Required when jpa.default.properties is set'
            ).build())
        }

        return errors
    }

To register the rule, add a ServiceLoader entry:

META-INF/services/io.micronaut.jsonschema.configuration.validator.ConfigurationRule

and list your implementation class name in that file.

CLI

Full classpath entry point

If the process classpath already contains all runtime dependencies, invoke:

java -cp <full-classpath> io.micronaut.jsonschema.configuration.validator.cli.ConfigurationJsonSchemaValidatorCli \
  --classpath <full-classpath> \
  --environments test \
  --out build/reports/config-schema \
  --format both

Minimal classpath bootstrap entry point

If you want to run with a minimal process classpath that contains only the configuration validator module, invoke:

java -cp <validator-module-only> io.micronaut.jsonschema.configuration.validator.cli.ConfigurationJsonSchemaValidatorCliBootstrap \
  --classpath <full-runtime-classpath> \
  --environments test \
  --out build/reports/config-schema

The bootstrap entry point only parses --classpath and forwards all remaining arguments to ConfigurationJsonSchemaValidatorCli.

7 Repository

You can find the source code of this project in this repository:

8 Release History

For this project, you can find a list of releases (with release notes) here: