Generation of JSON schema from Micronaut Configuration Properties#12377
Merged
Conversation
melix
reviewed
Feb 4, 2026
melix
left a comment
Contributor
There was a problem hiding this comment.
Looks correct even though I don't know enough of JSON Schema to tell if the generated format is ok. Comments are mostly around code style: the code doesn't look modern Java (no var, instanceof checks, final local variables, ...) and typical FQCN leftovers.
| return parts; | ||
| } | ||
|
|
||
| private void refEntry(Writer out) throws IOException { |
Contributor
There was a problem hiding this comment.
AFAICS helper methods could be static, or, maybe better, have a wrapper around Writer so that we don't have to pass out on every call.
919e828 to
552c038
Compare
8919fb7 to
28e2831
Compare
melix
approved these changes
Feb 4, 2026
|
dstepanov
approved these changes
Feb 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




This PR adds generation of JSON schema definitions for
@ConfigurationPropertiesand@EachPropery. The idea here is to use these definitions in build tooling (coming in a separate PR) to validate user configuration. AI was used in the generation of the implementation.Example JSON schema for
HttpServerConfiguration.:{ "$schema": "https:\/\/json-schema.org\/draft\/2020-12\/schema", "$id": "urn:micronaut:config:io.micronaut.http.server.HttpServerConfiguration", "title": "io.micronaut.http.server.HttpServerConfiguration", "description": "<p>A base {@link ConfigurationProperties} for servers.<\/p>", "x-micronaut": { "prefix": "micronaut.server", "type": "io.micronaut.http.server.HttpServerConfiguration", "kind": "configuration-properties" }, "type": "object", "properties": { "http-version": { "type": "string", "enum": [ "HTTP_1_0", "HTTP_1_1", "HTTP_2_0" ], "description": "Sets the HTTP version to use. Defaults to {@link HttpVersion#HTTP_1_1}.", "x-micronaut-javaType": "io.micronaut.http.HttpVersion", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.http-version" }, "thread-selection": { "type": "string", "enum": [ "AUTO", "MANUAL", "IO", "BLOCKING" ], "description": "Sets the {@link io.micronaut.scheduling.executor.ThreadSelection} model to use for the server. Default value MANUAL.", "x-micronaut-javaType": "io.micronaut.scheduling.executor.ThreadSelection", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.thread-selection" }, "default-charset": { "type": "string", "description": "The default charset to use", "x-micronaut-javaType": "java.nio.charset.Charset", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.default-charset" }, "port": { "type": "integer", "description": "Sets the port to bind to. Default value ({@value #DEFAULT_RANDOM_PORT})", "x-micronaut-javaType": "int", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.port", "default": 8080 }, "host": { "type": "string", "description": "Sets the host to bind to.", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.host" }, "read-timeout": { "type": "integer", "description": "Sets the default read timeout.", "x-micronaut-javaType": "java.lang.Integer", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.read-timeout" }, "max-request-size": { "type": "integer", "description": "Sets the maximum request size. Default value ({@value #DEFAULT_MAX_REQUEST_SIZE} => \/\/ 10MB)", "x-micronaut-javaType": "long", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.max-request-size", "default": 10485760 }, "max-request-buffer-size": { "type": "integer", "description": "Sets the maximum number of request bytes that will be buffered. Fully streamed requests can\n still exceed this value. Default value ({@value #DEFAULT_MAX_REQUEST_BUFFER_SIZE} => \/\/ 10MB).\n Currently limited to {@code 2^31}, if you need longer request bodies, stream them.<br>\n Note that there is always some internal buffering, so a very low value ({@code < ~64K}) will\n essentially act like a request size limit.", "x-micronaut-javaType": "long", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.max-request-buffer-size", "default": 10485760 }, "read-idle-timeout": { "type": "string", "format": "duration", "description": "Sets the amount of time a connection can remain idle without any reads occurring. Default value ({@value #DEFAULT_READ_IDLE_TIME_MINUTES} minutes).", "x-micronaut-javaType": "java.time.Duration", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.read-idle-timeout" }, "write-idle-timeout": { "type": "string", "format": "duration", "description": "Sets the amount of time a connection can remain idle without any writes occurring. Default value ({@value #DEFAULT_WRITE_IDLE_TIME_MINUTES} minutes).", "x-micronaut-javaType": "java.time.Duration", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.write-idle-timeout" }, "idle-timeout": { "type": "string", "format": "duration", "description": "Sets the idle time of connections for the server. Default value ({@value #DEFAULT_IDLE_TIME_MINUTES} minutes).", "x-micronaut-javaType": "java.time.Duration", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.idle-timeout" }, "server-header": { "type": "string", "description": "Sets the name of the server header.", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.server-header" }, "date-header": { "type": "boolean", "description": "Sets whether a date header should be sent back. Default value ({@value #DEFAULT_DATEHEADER}).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.date-header" }, "log-handled-exceptions": { "type": "boolean", "description": "Sets whether exceptions handled by either an error route or exception handler\n should still be logged. Default value ({@value #DEFAULT_LOG_HANDLED_EXCEPTIONS }).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.log-handled-exceptions", "default": false }, "client-address-header": { "type": "string", "description": "Which header stores the original client", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.client-address-header" }, "context-path": { "type": "string", "description": "Sets the context path for the web server.", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.context-path" }, "dual-protocol": { "type": "boolean", "description": "if dual protocol has been enabled or not", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.dual-protocol", "default": false }, "http-to-https-redirect": { "type": "boolean", "description": "if redirection from HTTP to HTTPS is enabled or not", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.http-to-https-redirect", "default": false }, "dispatch-options-requests": { "type": "boolean", "description": "Set to true to dispatch OPTIONS requests. Default value ({@value #DEFAULT_DISPATCH_OPTIONS_REQUESTS}.", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.dispatch-options-requests", "default": false }, "validate-url": { "type": "boolean", "description": "If the url should be validated by converting it to {@link java.net.URI}.", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.validate-url" }, "escape-html-url": { "type": "boolean", "description": "Browsers can send characters (such as {@code |}) which are not permitted under RFC 3986 as\n part of the request path. These characters are normally rejected by the server. If this\n setting is enabled, the server will escape these characters before parsing them using\n {@link java.net.URI} so that they are not rejected. Default off.", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.escape-html-url" }, "not-found-on-missing-body": { "type": "boolean", "description": "True if not-found should be returned on missing body. False to return an empty body.", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.not-found-on-missing-body" }, "semicolon-is-normal-char": { "type": "boolean", "description": "Sets whether the semicolon should be considered a normal character in the query.\n A \"normal\" semicolon is one that is not used as a parameter separator.", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.semicolon-is-normal-char", "default": false }, "max-params": { "type": "integer", "description": "the maximum parameter count.", "x-micronaut-javaType": "int", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration", "x-micronaut-path": "micronaut.server.max-params", "default": 1024 }, "multipart": { "type": "object", "properties": { "location": { "type": "string", "description": "Sets the location to store files.", "x-micronaut-javaType": "java.io.File", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$MultipartConfiguration", "x-micronaut-path": "micronaut.server.multipart.location" }, "max-file-size": { "type": "integer", "description": "Sets the max file size. Default value ({@value #DEFAULT_MAX_FILE_SIZE} => 1MB).", "x-micronaut-javaType": "long", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$MultipartConfiguration", "x-micronaut-path": "micronaut.server.multipart.max-file-size" }, "enabled": { "type": "boolean", "description": "Sets whether multipart processing is enabled. Default value ({@value #DEFAULT_ENABLED}).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$MultipartConfiguration", "x-micronaut-path": "micronaut.server.multipart.enabled" }, "disk": { "type": "boolean", "description": "Sets whether to buffer data to disk or not. Default value ({@value #DEFAULT_DISK}).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$MultipartConfiguration", "x-micronaut-path": "micronaut.server.multipart.disk" }, "mixed": { "type": "boolean", "description": "Sets whether to buffer data to disk if the size is greater than the\n threshold. Default value ({@value #DEFAULT_MIXED}).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$MultipartConfiguration", "x-micronaut-path": "micronaut.server.multipart.mixed" }, "threshold": { "type": "integer", "description": "Sets the amount of data that should be received that will trigger\n the data to be stored to disk. Default value ({@value #DEFAULT_THRESHOLD}).", "x-micronaut-javaType": "long", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$MultipartConfiguration", "x-micronaut-path": "micronaut.server.multipart.threshold" } } }, "cors": { "type": "object", "properties": { "enabled": { "type": "boolean", "description": "Sets whether CORS is enabled. Default value ({@value #DEFAULT_ENABLED})", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$CorsConfiguration", "x-micronaut-path": "micronaut.server.cors.enabled" }, "localhost-pass-through": { "type": "boolean", "description": "Sets whether localhost pass-through is enabled. Default value {@value #DEFAULT_LOCALHOST_PASS_THROUGH}.\n Setting this to true will allow requests to be made to localhost from any origin.", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$CorsConfiguration", "x-micronaut-path": "micronaut.server.cors.localhost-pass-through" }, "configurations": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Sets the CORS configurations.", "x-micronaut-javaType": "java.util.Map", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$CorsConfiguration", "x-micronaut-path": "micronaut.server.cors.configurations" }, "single-header": { "type": "boolean", "description": "Sets whether CORS header values should be joined into a single header. Default value ({@value #DEFAULT_SINGLE_HEADER}).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$CorsConfiguration", "x-micronaut-path": "micronaut.server.cors.single-header" } } }, "host-resolution": { "type": "object", "properties": { "host-header": { "type": "string", "description": "The host header name", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HostResolutionConfiguration", "x-micronaut-path": "micronaut.server.host-resolution.host-header" }, "protocol-header": { "type": "string", "description": "The protocol header name", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HostResolutionConfiguration", "x-micronaut-path": "micronaut.server.host-resolution.protocol-header" }, "port-header": { "type": "string", "description": "The port header name", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HostResolutionConfiguration", "x-micronaut-path": "micronaut.server.host-resolution.port-header" }, "port-in-host": { "type": "boolean", "description": "If the host header supports a port", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HostResolutionConfiguration", "x-micronaut-path": "micronaut.server.host-resolution.port-in-host" }, "allowed-hosts": { "type": "array", "items": { "type": "string" }, "description": "The list of hosts to validate the resolved host against.", "x-micronaut-javaType": "java.util.List", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HostResolutionConfiguration", "x-micronaut-path": "micronaut.server.host-resolution.allowed-hosts" } } }, "locale-resolution": { "type": "object", "properties": { "fixed": { "type": "string", "description": "Set the language tag for the locale. Supports BCP 47 language\n tags (e.g. \"en-US\") and ISO standard (e.g \"en_US\").", "x-micronaut-javaType": "java.util.Locale", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HttpLocaleResolutionConfigurationProperties", "x-micronaut-path": "micronaut.server.locale-resolution.fixed" }, "session-attribute": { "type": "string", "description": "Sets the key in the session to look for the locale.", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HttpLocaleResolutionConfigurationProperties", "x-micronaut-path": "micronaut.server.locale-resolution.session-attribute" }, "default-locale": { "type": "string", "description": "Sets the locale that will be used if the locale cannot be\n resolved through any means. Defaults to the system default.", "x-micronaut-javaType": "java.util.Locale", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HttpLocaleResolutionConfigurationProperties", "x-micronaut-path": "micronaut.server.locale-resolution.default-locale" }, "cookie-name": { "type": "string", "description": "Sets the name of the cookie that is used to store the locale.", "x-micronaut-javaType": "java.lang.String", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HttpLocaleResolutionConfigurationProperties", "x-micronaut-path": "micronaut.server.locale-resolution.cookie-name" }, "header": { "type": "boolean", "description": "Set to true if the locale should be resolved from the `Accept-Language` header.\n Default value ({@value #DEFAULT_HEADER_RESOLUTION}).", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$HttpLocaleResolutionConfigurationProperties", "x-micronaut-path": "micronaut.server.locale-resolution.header" } } }, "responses": { "type": "object", "properties": { "file": { "type": "object", "properties": { "cache-seconds": { "type": "integer", "description": "Cache Seconds. Default value ({@value #DEFAULT_CACHESECONDS}).", "x-micronaut-javaType": "int", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$FileTypeHandlerConfiguration", "x-micronaut-path": "micronaut.server.responses.file.cache-seconds" }, "cache-control": { "type": "object", "properties": { "public": { "type": "boolean", "description": "Sets whether the cache control is public. Default value ({@value #DEFAULT_PUBLIC_CACHE})", "x-micronaut-javaType": "boolean", "x-micronaut-sourceType": "io.micronaut.http.server.HttpServerConfiguration$FileTypeHandlerConfiguration$CacheControlConfiguration", "x-micronaut-path": "micronaut.server.responses.file.cache-control.public" } } } } } } } } }