1. Introduction
In this tutorial, we’ll develop JSON Schemas from Java utilizing the Java JSON Schema Generator collection.
Initially, we’ll see just how to produce straightforward as well as recursive JSON Schemas. Next off, we’ll consider the various schema setups offered. Going on, we’ll together obtain JSON Schemas from several of the collection’s components: Jackson as well as Jakarta recognition Lastly, we’ll establish a Virtuoso plugin to have JSON Schemas at the Virtuoso produce objective
2. Configuration
Allowed’s established the needed dependences for our task.
2.1. Core Dependence
Initially, allow’s set up jsonschema-generator:
<< dependence>>.
<< groupId>> com.github.victools<.
<< artifactId>> jsonschema-generator<.
<< variation>> 4.31.1<.
<
It has the primary APIs for schema generation as well as setup.
2.2. Components
Following, we'll set up 3 components to produce JSON Schema associates from course notes. Allow's begin by including jsonschema-module-jackson:
<< dependence>>.
<< groupId>> com.github.victools<.
<< artifactId>> jsonschema-module-jackson<.
<< variation>> 4.31.1<.
<
This component obtains JSON Schema associates from Jackson notes
Proceeding, we'll set up jsonschema-module-jakarta-validation to obtain the schema from Jakarta recognition notes:
<< dependence>>.
<< groupId>> com.github.victools<.
<< artifactId>> jsonschema-module-jakarta-validation<.
<< variation>> 4.31.1<.
<
2.3. Virtuoso Plugin
Lastly, allow's include jsonschema-maven-plugin:
<< plugin>>.
<< groupId>> com.github.victools<.
<< artifactId>> jsonschema-maven-plugin<.
<< variation>> 4.31.1<.
<< implementations>>.
<< implementation>>.
<< objectives>>.
<< objective>> produce<.
<.
<.
<.
<
In The Future, we'll specify the setup access It takes the courses to produce a schema from, the schema setup, as well as the components to be made use of.
Allowed's note that considering that variation 4.7 of Java JSON Schema Generator, it's very advised that components as well as plugins utilize the very same variation as the core dependence.
3. Essentials
In this area, we'll check out the foundation of the jsonschema-generator by developing straightforward as well as recursive schemas.
3.1. Easy Schema
Allow's specify an Short Article:
public course Short article {
exclusive UUID id;
exclusive String title;
exclusive String web content;
exclusive Day createdAt;
exclusive Location location;
// getters as well as setters left out.
}
We'll produce a schema from the Short Article course:
SchemaGeneratorConfigBuilder configBuilder = brand-new SchemaGeneratorConfigBuilder( SchemaVersion.DRAFT _ 2020_12, OptionPreset.PLAIN _ JSON);
SchemaGeneratorConfig config = configBuilder.with( Option.EXTRA _ OPEN_API_FORMAT_VALUES)
. without( Option.FLATTENED _ ENUMS_FROM_TOSTRING)
. develop();
SchemaGenerator generator = brand-new SchemaGenerator( config);
JsonNode jsonSchema = generator.generateSchema( Article.class);
Below, we're targeting DRAFT_2020-12, the most recent JSON Schema draft currently. Otherwise defined, the schema will certainly be produced utilizing DRAFT-7 requirements.
The PLAIN_JSON OptionPreset holds a great deal of default setups to utilize every non-static course area for schema generation. The various other offered presets are JAVA_OBJECT as well as FULL_DOCUMENTATION The initial consists of public areas as well as approaches in the schema while the 2nd consists of all areas as well as public approaches. Otherwise defined, the predetermined defaults to FULL_DOCUMENTATION
The produced schema appreciates the DRAFT_2020-12 framework:
{
"$ schema":" https://json-schema.org/draft/2020-12/schema",.
" kind":" item",.
" residential or commercial properties": {
" location": {
" kind":" string",.
" enum":[
"JAVA",
"KOTLIN",
"SCALA",
"LINUX"
]
},.
" web content": {
" kind":" string".
},.
" createdAt": {
" kind":" string",.
" style":" date-time".
},.
" id": {
" kind":" string",.
" style":" uuid".
},.
" title": {
" kind":" string".
}
}
}
Allow's keep in mind a number of points below. Initially, Java Day as well as UUID are strings in the schema. The good news is, their actual kinds are defined in the area style, many thanks to the EXTRA_OPEN_API_FORMAT_VALUES generator alternative It includes additional info for unique JSON Schema strings.
Lastly, Java enums are stood for by calling their name() approach.
3.2. Recursive Schema
Allowed's have an Writer course:
public course Writer {
exclusive UUID id;
exclusive String name;
exclusive String duty;
exclusive Listing<< AuthoredArticle> > short articles;
// getters, setters, left out.
}
An writer has a listing of AuthoredArticle Alternatively, an AuthoredArticle has an writer:
public course AuthoredArticle {
exclusive Writer writer;
// getters as well as setters left out.
}
Maintaining all setups from the previous area, the schema for the AuthoredArticle course is a recursive schema
Remarkably, the short articles area of the writer residential or commercial property recommendations the real schema being produced:
{
" writer": {
" kind":" item",.
" residential or commercial properties": {
" short articles": {
" kind":" variety",.
" things": {
"$ ref":" #".
}
}
}
}
}
This sort of round referencing is permitted by the requirements. Nonetheless, a $ ref can not indicate one more $ ref
4. Arrangement
In the previous area, we made use of some integrated presets Currently, we'll see just how to accomplish fine-grained setups.
Initially, we'll tailor the produced schema characteristics utilizing private setups After that, we'll have a preview at progressed setups
4.1. Specific Arrangement
Allowed's configure schema areas for our Writer course:
configBuilder.forFields()
. withRequiredCheck( area -> > field.getAnnotationConsideringFieldAndGetter( Nullable.class) == null)
. withArrayUniqueItemsResolver( range -> > scope.getType(). getErasedType() == (List.class)? real: null);
The resulting schema marks residential or commercial properties that aren't nullable as called for. It additionally makes the short articles residential or commercial property a special variety:
{
"$ schema":" https://json-schema.org/draft/2020-12/schema",.
" kind":" item",.
" residential or commercial properties": {
" short articles": {
" uniqueItems": real,.
" kind":" variety",.
" things": {
" kind":" item",.
" residential or commercial properties": {
" location": {
" kind":" string",.
" enum":[
"JAVA",
"KOTLIN",
"SCALA",
"LINUX"
]
},.
" writer": {
"$ ref":" #".
},.
" web content": {
" kind":" string".
},.
" createdAt": {
" kind":" string",.
" style":" date-time",.
" default":1690565063847.
},.
" id": {
" kind":" string",.
" style":" uuid".
},.
" title": {
" kind":" string".
}
},.
" called for":[
"area",
"author",
"content",
"createdAt",
"id",
"title"
]
},.
" default":[
]
},.
" id": {
" kind":" string",.
" style":" uuid".
},.
" name": {
" kind":" string".
},.
" duty": {
" kind":" string".
}
},.
" called for":[
"articles",
"id",
"name",
"role"
]
}
The schema over has additionally default worths for the createdAt as well as short articles residential or commercial properties. It results from our setup for kinds:
configBuilder.forTypesInGeneral()
. withArrayUniqueItemsResolver( range -> > scope.getType(). getErasedType() == (List.class)? real: null)
. withDefaultResolver( range -> > scope.getType(). getErasedType() == List.class? Collections.EMPTY _ LISTING: void)
. withDefaultResolver( range -> > scope.getType(). getErasedType() == Date.class? Date.from( Instant.now()): void);
The ArrayUniqueItemsResolver makes sure that a range is significant distinct if it was produced from a Listing kind.
Similar To we have actually set up areas as well as kinds, we're additionally able to set up approaches:
configBuilder.forMethods()
. withRequiredCheck( approach -> > method.getAnnotationConsideringFieldAndGetter( NotNull.class)!= null);
We note areas annotated @NotNull as called for. They are additionally called for if that comment gets on their getter.
Besides, for every setup, returning void does not establish the area in the schema.
4.2. Advanced Arrangement
In this area, we'll utilize our AdvancedArticle course:
public course AdvancedArticle {
exclusive UUID id;
exclusive String title;
exclusive String web content;
@AllowedTypes( {Timestamp.class, String.class, Date.class} ).
exclusive Item createdAt;
exclusive Location location;
// getters as well as setters left out.
}
Advanced setup is the supreme turn to tailor JSON Schema generation. It's specifically helpful when we require characteristics that aren't given by the private setup:
configBuilder.forFields()
. withInstanceAttributeOverride(( node, area, context) -> > node.put(" readOnly", field.getDeclaredType(). isInstanceOf( UUID.class)));
Below, we have actually included a readOnly credit to every residential or commercial property. It defaults to incorrect besides the UUID course:
{
" id": {
" kind":" string",.
" style":" uuid",.
" readOnly": real.
},.
" title": {
" kind":" string",.
" readOnly": incorrect.
}
}
An additional fascinating setup is the capacity to define permitted key ins an offered area. In our AdvancedArticle course, the createdAt residential or commercial property approves both Day as well as Timestamp kinds:
configBuilder.forFields()
. withTargetTypeOverridesResolver( area -> > Optional.ofNullable( field.getAnnotationConsideringFieldAndGetterIfSupported( AllowedTypes.class))
. map( AllowedTypes:: worth)
. map( Stream:: of)
. map( stream -> > stream.map( subtype -> > field.getContext(). willpower( subtype)))
. map( stream -> > stream.collect( Collectors.toList()))
. orElse( void));
Under the hood, the TargetTypeOverride course refines every area annotated @AllowedTypes. After that, it includes those kinds to the resulting createdAt residential or commercial property:
{
" createdAt": {
" anyOf":[
{
"type":"object",
"properties":{
"nanos":{
"type":"integer",
"format":"int32",
"readOnly":false
}
},
"readOnly":false
},
{
"type":"string",
"format":"date-time",
"readOnly":false
}
]
}
}
As we can see, the resulting union kind is defined by the anyOf feature.
Allow's bear in mind that the setup opportunities are countless. We can also include personalized kind interpretations or personalized residential or commercial property interpretations It depends on us to pick which degree of modification to cover our requirements.
5. Components
Java JSON Schema Generator permits us to team setups in components. We can develop our very own components by carrying out the Component user interface In the following areas, we'll see just how to utilize several of the integrated components We'll check out Jackson as well as Jakarta Recognition components.
5.1. Jackson
The Jackson component refines Jackson notes to develop JSON Schema setup. Allow's consider our Individual course:
course Individual {
@JsonProperty( gain access to = JsonProperty.Access.READ _ ONLY).
UUID id;
@JsonProperty( gain access to = JsonProperty.Access.READ _ COMPOSE, called for = real).
String name;
@JsonProperty( gain access to = JsonProperty.Access.READ _ COMPOSE, called for = real).
String last name;
@JsonProperty( gain access to = JsonProperty.Access.READ _ COMPOSE, called for = real).
Address address;
@JsonIgnore.
String fullName;
@JsonProperty( gain access to = JsonProperty.Access.READ _ ONLY).
Day createdAt;
@JsonProperty( gain access to = JsonProperty.Access.READ _ WRITE).
Listing<< Individual> > good friends;
// getters as well as setters left out.
}
Allow's include JacksonModule to our SchemaGeneratorConfigBuilder:
JacksonModule component = brand-new JacksonModule( RESPECT_JSONPROPERTY_REQUIRED);
SchemaGeneratorConfigBuilder configBuilder = brand-new SchemaGeneratorConfigBuilder( DRAFT_2020_12, PLAIN_JSON). with( component)
. with( EXTRA_OPEN_API_FORMAT_VALUES);
SchemaGenerator generator = brand-new SchemaGenerator( configBuilder.build());.
JsonNode jsonSchema = generator.generateSchema( Person.class);
The component approves particular alternatives for more modification. The RESPECT_JSONPROPERTY_REQUIRED alternative advises the component to think about JsonProperty.Access in the generation of the readOnly area in the schema.
The resulting schema has called for as well as readOnly areas effectively established:
{
" kind":" item",.
" residential or commercial properties": {
" createdAt": {
" kind":" string",.
" style":" date-time",.
" readOnly": real.
},.
" good friends": {
" kind":" variety",.
" things": {
"$ ref":" #".
}
},.
" id": {
" kind":" string",.
" style":" uuid",.
" readOnly": real.
}
},.
" called for":[
"address",
"name",
"surname"
]
}
Non-annotated residential or commercial properties as well as residential or commercial properties annotated with @JsonIgnore are disregarded. Embedded areas for Address course as well as recursive schema for good friends residential or commercial property are effectively referenced.
5.2. Jakarta Recognition
Jakarta Recognition component creates schema setup from jakarta.validation.constraints notes. Allow's embellish our Individual course:
course Individual {
@NotNull.
UUID id;.
@NotNull.
String name;.
@NotNull.
@Email.
@Pattern( regexp=" b[A-Za-z0-9._%+-][email protected] . com b").
String e-mail;.
@NotNull.
String last name;.
@NotNull.
Address address;.
@Null.
String fullName;.
@NotNull.
Day createdAt;.
@Size( max = 10).
Listing<< Individual> > good friends;.
// getters as well as setters left out
}
Following, allow's set up JakartaValidationModule:
JakartaValidationModule component = brand-new JakartaValidationModule( NOT_NULLABLE_FIELD_IS_REQUIRED, INCLUDE_PATTERN_EXPRESSIONS);.
SchemaGeneratorConfigBuilder configBuilder = brand-new SchemaGeneratorConfigBuilder( DRAFT_2020_12, PLAIN_JSON). with( component);.
SchemaGenerator generator = brand-new SchemaGenerator( configBuilder.build());.
JsonNode jsonSchema = generator.generateSchema( Person.class);
The component additionally takes recognition teams by means of its forValidationGroups() approach.
The NOT_NULLABLE_FIELD_IS_REQUIRED alternative makes areas annotated with @NotNull called for. Many thanks to the INCLUDE_PATTERN_EXPRESSIONS, the produced schema consists of a pattern area for all residential or commercial properties annotated with @Pattern:
{
" kind":" item",.
" residential or commercial properties": {
" createdAt": {
" kind":" string".
},.
" e-mail": {
" kind":" string",.
" style":" e-mail",.
" pattern":" b[A-Za-z0-9._%+-][email protected] . com b".
},.
" good friends": {
" maxItems":10,.
" kind":" variety",.
" things": {
"$ ref":" #".
}
},.
" fullName": {
" kind":[
"string",
"null"
]
}
},.
" called for":[
"createdAt",
"email",
"id",
"name",
"surname"
]
}
Allowed's note that the e-mail residential or commercial property has a style area because of it being annotated with @Email in the Individual course. Furthermore, the good friends residential or commercial property has its maxItems area effectively established.
6. Virtuoso Plugin
Java JSON Schema Generator has an Expert plugin to produce schema from our develop procedure. Allow's set up the plugin:
<< plugin>>.
<< groupId>> com.github.victools<.
<< artifactId>> jsonschema-maven-plugin<.
<< variation>> 4.31.1<.
<< implementations>>.
<< implementation>>.
<< objectives>>.
<< objective>> produce<.
<.
<.
<.
<< setup>>.
<< packageNames>>.
<< packageName>> com.baeldung.jsonschemageneration.plugin<.
<.
<< classNames>>.
<< className>> com.baeldung.jsonschemageneration.plugin.Person<.
<.
<< schemaVersion>> DRAFT_2020_12<.
<< schemaFilePath>> src/main/resources/ schemas<.
<< schemaFileName> > {1}/ {0}. json<.
<< failIfNoClassesMatch>> real<.
<< alternatives>>.
<< predetermined>> PLAIN_JSON<.
<< made it possible for>>.
<< alternative>> DEFINITIONS_FOR_ALL_OBJECTS<.
<< alternative>> FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT<.
<.
<< handicapped>> SCHEMA_VERSION_INDICATOR<.
<.
<< components>>.
<< component>>.
<< name>> Jackson<.
<< alternatives>>.
<< alternative>> RESPECT_JSONPROPERTY_REQUIRED<.
<.
<.
<< component>>.
<< name>> JakartaValidation<.
<< alternatives>>.
<< alternative>> NOT_NULLABLE_FIELD_IS_REQUIRED<.
<< alternative>> INCLUDE_PATTERN_EXPRESSIONS<.
<.
<.
<.
<.
<
We'll produce a schema based upon the Individual course situated in the com.baeldung.jsonschemageneration.plugin bundle. We can still specify the components to utilize, as well as pass them some alternatives. Yet, the plugin does not permit setting up alternatives for personalized components.
Lastly, the produced documents name pattern is made up of {1} which is the bundle name as well as {0} , the course name. It will certainly be found at srcmainresourcesschemascombaeldungjsonschemagenerationpluginPerson.json To produce it, allow's run mvn assemble
The resulting schema aspects every problem defined in the plugin setup.
7. Final Thought
In this post, we have actually made use of Java JSON Schema Generator to produce JSON Schemas in Java. After some fundamentals of schema generation, we have actually seen just how to tweak the schema setup. Next off, we checked out numerous components from the collection to produce JSON schema. Eventually, we have actually developed JSON Schemas as component of our Virtuoso produce objective utilizing a devoted plugin.
As constantly, the code for this post is offered over on GitHub