victools/jsonschema-generator

repository·main·Indexed 20 days ago

https://github.com/victools/jsonschema-generator

A Java library that generates JSON Schemas (Draft 6 through Draft 2020-12) from Java classes using Jackson. It features a modular architecture to derive schema constraints and metadata from annotation frameworks such as Jackson, Jakarta Validation, Javax Validation, and Swagger. The project includes a Maven plugin (jsonschema-maven-plugin) for build integration and a Bill of Materials (jsonschema-generator-bom) for dependency management.

Tokens
24.7K
Snippets
57
Records
69
Agent score
68%

What's inside victools-jsonschema-generator

  1. Overview of victools/jsonschema-generator

    main

    The victools/jsonschema-generator is a library designed to generate JSON Schemas (supporting Draft 6, Draft 7, Draft 2019-09, or Draft 2020-12) from Java code.

    Beyond documenting JSON structures, it can also be used to document Java APIs by including methods and their associated return values in the schema. The project is distributed as multiple independent artifacts via Maven Central and Sonatype.

  2. Use Modules to configure the JSON Schema Generator

    main

    A Module is a convenient way to include multiple individual configurations or advanced configurations at once. Instead of manually adding many separate Options, you can use a Module as an entry-point for grouping configurations or plugging in external dependencies.

    To apply a module, use the SchemaGeneratorConfigBuilder.with(Module) method during the configuration phase.

    // Example pattern for applying a module
    SchemaGeneratorConfig config = new SchemaGeneratorConfigBuilder()
        .with(SomeModule.INSTANCE) // Replace with a specific Module
        .build();
  3. Configure Enum representation in schemas

    main

    Enums can be represented in several ways depending on your requirements:

    1. Flattened Enums (Option.FLATTENED_ENUMS in OptionPreset.PLAIN_JSON): Defines an enum as a string type with an enum array of values using the name() method. If only one value exists, it uses const.
    2. Simplified Enums (Option.SIMPLIFIED_ENUMS in OptionPreset.JAVA_OBJECT or OptionPreset.FULL_DOCUMENTATION): Treats enums like regular classes but lists possible values in an enum or const field on the name() method.
    3. Standard Class Treatment: If neither option is used, enums are treated like any other class.
    4. Jackson-specific options:
      • JacksonOption.FLATTENED_ENUMS_FROM_JSONVALUE: Uses the @JsonValue annotated method for values.
      • JacksonOption.FLATTENED_ENUMS_FROM_JSONPROPERTY: Uses the @JsonProperty annotation for values.
    5. Custom Logic: Use EnumModule to provide custom serialization logic (e.g., using an ObjectMapper).
    ObjectMapper objectMapper = new ObjectMapper();
    configBuilder.with(new EnumModule(possibleEnumValue -> {
        try {
            String valueInQuotes = objectMapper.writeValueAsString(possibleEnumValue);
            return valueInQuotes.substring(1, valueInQuotes.length() - 1);
        } catch (JsonProcessingException ex) {
            throw new IllegalStateException(ex);
        }
    }));
  4. Configure individual schema attributes via SchemaGeneratorConfigBuilder

    main

    You can control how specific JSON Schema attributes (like title, description, required, etc.) are resolved by defining individual configurations. These configurations can be applied at three different scopes:

    1. General Types: Use SchemaGeneratorConfigBuilder.forTypesInGeneral() to apply logic to any encountered type.
    2. Fields: Use SchemaGeneratorConfigBuilder.forFields() to apply logic to specific class fields.
    3. Methods: Use SchemaGeneratorConfigBuilder.forMethods() to apply logic to specific method return values.

    Important Rules for Resolvers:

    • Null handling: Returning null in a resolver means that specific configuration does not apply, and the generator will consult the next available configuration of that kind.
    • Order of precedence: Configurations are consulted in the order they are set on the SchemaGeneratorConfigBuilder. Option settings are always consulted last.
    • Container types: When encountering a 'container' type (like an array or a Collection), individual configurations for fields or methods are called twice. You may need to handle cases where FieldScope.isFakeContainerItemScope() or MethodScope.isFakeContainerItemScope() returns true to avoid duplicate or incorrect metadata for the items within the container.
    SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09);
    configBuilder.forField()
        .withTitleResolver(field -> field.getName() + " = "
                + (field.isFakeContainerItemScope() ? "(fake) " : "(real) ")
                + field.getSimpleTypeDescription())
        .withDescriptionResolver(field -> "original type = "
                + field.getContext().getSimpleTypeDescription(field.getDeclaredType()));
    
    JsonNode mySchema = new SchemaGenerator(configBuilder.build())
            .generateSchema(MyClass.class);
  5. Use Modules to extend plugin configuration

    main

    The <modules> tag allows you to include standard modules or your own custom modules to further configure the schema generation.

    Standard Modules

    You can include standard modules and provide specific options for them:

    <modules>
        <module>
            <name>Jackson</name>
            <options>
                <option>FLATTENED_ENUMS_FROM_JSONVALUE</option>
            </options>
        </module>
    </modules>

    Custom Modules

    You can provide a fully qualified class name for a custom module. The class must:

    1. Implement the Module interface.
    2. Have a default constructor.
    3. Be available on the plugin's classpath.

    Note: You cannot configure specific options for custom modules via the XML; you must handle configuration logic within the module's Java code.

    <modules>
        <module>
            <className>com.myOrg.myApp.CustomModule</className>
        </module>
    </modules>
  6. Understand OptionPreset usage

    main

    The library provides three standard OptionPresets to simplify configuration based on your target use case:

    • FULL_DOCUMENTATION (F_D): Optimized for comprehensive documentation. Includes most features like simplified enums/optionals, static/void methods, and non-public field access.
    • JAVA_OBJECT (J_O): Optimized for representing standard Java objects. Focuses on fields, getters, and common Java types.
    • PLAIN_JSON (P_J): Optimized for standard JSON schemas. Includes schema version indicators, additional fixed types, and flattened enums/optionals/suppliers, but excludes many Java-specific metadata options like static fields or methods.
  7. Available victools modules for schema derivation

    main

    The core jsonschema-generator can be extended with modules that derive JSON Schema attributes from specific annotations. Use these modules to automatically include metadata like descriptions, constraints, or subtypes in your generated schema:

    • jsonschema-module-jackson: Derives attributes from Jackson annotations (e.g., description, property name overrides, @JsonIgnore).
    • jsonschema-module-jakarta-validation: Derives attributes from jakarta.validation.constraints (e.g., nullable, minimum, maximum, minItems, maxItems, minLength, maxLength).
    • jsonschema-module-javax-validation: Derives attributes from javax.validation (e.g., nullable, minimum, maximum, minItems, maxItems, minLength, maxLength).
    • jsonschema-module-swagger-1.5: Derives attributes from Swagger 1.5.x annotations.
    • jsonschema-module-swagger-2: Derives attributes from Swagger 2.x @Schema annotations.
  8. Select classes for JSON schema generation

    main

    You can specify which classes should be processed using several methods:

    By Name or Package

    Use <classNames> and/or <packageNames> to define targets. You can also use <excludeClassNames> to filter them out.

    Supported formats for names and packages:

    • Absolute paths: Use dots (.) as separators (e.g., com.myOrg.myApp.MyClass).
    • Glob patterns: Use slashes (/) as separators and standard placeholders like ?, *, or ** (e.g., com/myOrg/myApp/package?).

    To skip specific types, use:

    • <skipAbstractTypes>true</skipAbstractTypes>
    • <skipInterfaces>true</skipInterfaces>

    By Annotations

    Use the <annotations> element to include all classes that carry at least one of the specified annotations. If used alongside <classNames> or <packageNames>, a class must match both the name/package criteria AND have at least one of the specified annotations.

    Restricting the Classpath

    Control which dependencies are scanned using the <classpath> element:

    • PROJECT_ONLY: Only source files of the current project.
    • WITH_COMPILE_DEPENDENCIES: Project source plus compile dependencies.
    • WITH_RUNTIME_DEPENDENCIES: Project source plus runtime dependencies (default).
    • WITH_ALL_DEPENDENCIES: All dependencies.

    Note: If no classes match your criteria, the plugin will fail by default. Set <failIfNoClassesMatch>false</failIfNoClassesMatch> to prevent this.

    <configuration>
        <classNames>com.myOrg.myApp.MyClass</classNames>
        <packageNames>
            <packageName>com.myOrg.myApp.package1</packageName>
            <packageName>com.myOrg.myApp.package2</packageName>
        </packageNames>
        <excludeClassNames>com.myOrg.myApp.package2.HiddenClass</excludeClassNames>
    </configuration>
  9. Use the Bill of Materials (BOM) to manage dependencies

    main

    The jsonschema-generator-bom is used to ensure a compatible combination of the main jsonschema-generator and its various standard modules. By using the BOM, you can manage versions centrally in your <dependencyManagement> section, allowing you to declare individual dependencies in your <dependencies> section without specifying explicit version numbers.

    <!-- 1. Include BOM in <dependencyManagement> -->
    <dependencyManagement>
        <dependency>
            <groupId>com.github.victools</groupId>
            <artifactId>jsonschema-generator-bom</artifactId>
            <version>[5.0.0,6.0.0)</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencyManagement>
    
    <!-- 2. Reference dependencies without versions -->
    <dependencies>
        <dependency>
            <groupId>com.github.victools</groupId>
            <artifactId>jsonschema-generator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.github.victools</groupId>
            <artifactId>jsonschema-module-jackson</artifactId>
        </dependency>
    </dependencies>
  10. Install the victools:jsonschema-maven-plugin

    main

    To incorporate JSON Schema generation from your code into your Maven build process, add the jsonschema-maven-plugin to your pom.xml. You must specify the generate goal within an <execution> block.

    By default, the plugin runs during the compile phase. If you need to include test classes or specific test-related configurations, you must manually specify a later <phase> such as test-compile.

    <plugin>
        <groupId>com.github.victools</groupId>
        <artifactId>jsonschema-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>generate</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <!-- Configuration goes here -->
        </configuration>
    </plugin>
  11. Use the Swagger 1.5 Module to derive JSON Schema from Swagger annotations

    main

    The victools:jsonschema-module-swagger-1.5 module allows you to automatically derive JSON Schema attributes from Swagger 1.5.x annotations (like @ApiModel and @ApiModelProperty).

    To use the module, instantiate a SwaggerModule with your desired SwaggerOption values and pass it to a SchemaGeneratorConfigBuilder using the .with(module) method.

    Key behaviors:

    • Attributes derived from @ApiModelProperty on fields are also applied to their getter methods, and vice versa.
    • The module supports both opt-in and opt-out configurations via SwaggerOption.
    import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
    import com.github.victools.jsonschema.generator.SchemaVersion;
    import com.github.victools.jsonschema.module.swagger15.SwaggerModule;
    import com.github.victools.jsonschema.module.swagger15.SwaggerOption;
    
    // Initialize the module with specific options
    SwaggerModule module = new SwaggerModule(
            SwaggerOption.ENABLE_PROPERTY_NAME_OVERRIDES,
            SwaggerOption.IGNORING_HIDDEN_PROPERTIES
    );
    
    // Register the module with the config builder
    SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_2019_09)
        .with(module);