openapi-to-java-records-mustache-templates

Generate Java Records from OpenAPI Specifications

O2JRM Logo Maven Central Version MvnRepository JUnit Test Suite OpenSSF Scorecard OpenSSF Best Practices

Project containing Mustache-templates used by openapi-generator-maven-plugin to generate Java Records from OpenAPI Specifications.

This project contains the mustache templates.

Apache License 2.0

This project is licensed under the Apache License 2.0.

Support the Project

If you find this project useful, please ⭐ Star ⭐ it and share it with others! This is the best way to show appreciation for this project - Thank you! ❤️

If you have feedback or suggestions, please share it in either Discussions or Issues!

This project is, and will continue to be, solely maintained by Chrimle. While direct code contributions are disallowed, your feedback is the most valuable contribution - please share it!

Getting Started

If you want a more detailed guide with simple examples to get started, check out the Wiki-page Beginner Guide (Step-by-Step).

It is strongly recommended to import the mustache templates as a dependency. It has officially been published to:

<dependency>
    <groupId>io.github.chrimle</groupId>
    <artifactId>openapi-to-java-records-mustache-templates</artifactId>
    <version>3.5.0</version>
</dependency>

The Maven artifact only contains the .mustache template files and a LICENSE.txt. No other files are included in the imported artifact.

Use a plugin such as maven-dependency-plugin to easily unpack the .mustache files.

While it is possible to download the Mustache templates directly from GitHub, this approach is not recommended. Templates obtained this way are not guaranteed to be versioned correctly and is explicitly exempt from the Semantic Versioning considerations.

Use the .mustache templates when generating

Place the file(s) in desired directory. Then, in the Maven build configuration, set the property <templateDirectory> to the directory path. Example:

<build>
  <plugins>
    <plugin>
      <groupId>org.openapitools</groupId>
      <artifactId>openapi-generator-maven-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>generate</goal>
          </goals>
          <configuration>
            <inputSpec><!-- Relative directory path to the openapi.yaml file --></inputSpec>
            <templateDirectory><!-- Relative directory path to the mustache templates --></templateDirectory>
            <output><!-- Relative directory path to where generated classes should be placed --></output>
          </configuration>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Additional Configurations

The generated classes are customizable by using <configuration>-properties.

In this example, each generated class field will be annotated with Jakarta Bean Validation annotations.

  <configuration>
    <!-- ... more configurations ... -->
    <configOptions>
      <useBeanValidation>true</useBeanValidation>
      <!-- ... more configOptions ... -->
    </configOptions>
  </configuration>

See Supported ‘openapi‐generator‐maven‐plugin’ Configuration options

OpenAPI Specification

components:
  schemas:
    Name:
      description: Name Information
      type: object
      required:
        - firstName
        - lastName
      properties:
        firstName:
          description: First Name
          type: string
          minLength: 2
        lastName:
          description: Last Name
          type: string
          minLength: 2
        middleName:
          description: Middle Name
          type: string
          nullable: true
    Person:
      description: Personal information
      deprecated: true
      type: object
      required:
        - name
        - age
        - gender
        - height
        - ssn
        - aliases
        - email
        - trackingCode
        - uuid
      properties:
        name:
          description: Name
          type: object
          $ref: '#/components/schemas/Name'
        age:
          description: Age (years)
          type: integer
          minimum: 0
          maximum: 100
        gender:
          description: Gender
          type: string
          enum:
            - Male
            - Female
        height:
          description: Height (m)
          type: number
          pattern: float
          minimum: 0
        legalGuardian:
          description: Legal Guardian
          type: object
          $ref: '#/components/schemas/Person'
        ssn:
          description: Social Security Number
          type: string
          pattern: '^\d{3}-\d{2}-\d{4}$'
        aliases:
          description: Known Aliases
          type: array
          uniqueItems: true
          minItems: 1
          maxItems: 3
          items:
            type: string
        telephoneNumber:
          description: Telephone Number
          type: string
          nullable: true
        email:
          description: Email Address
          type: string
          format: email
        trackingCode:
          description: Tracking code for Web analytics
          type: string
          minLength: 5
          maxLength: 50
          default: "utm_source=default"
        uuid:
          description: An Universally Unique Identifier
          type: string
          format: uuid

See Supported OpenAPI Specification properties

Generate models

Compile the project, for example via:

mvn compile

Further information about how to generate models can be found on openapi-generator-maven-plugin.

Generated Java Record

Unless the configuration property <output> has been set, the generated classes should be found under ./target/generated-sources/openapi.

package io.github.chrimle.o2jrm;

/**
 * Personal information
 *
 * @deprecated
 * @param name Name.
 * @param age Age (years)
 * @param gender Gender
 * @param height Height (m)
 * @param legalGuardian Person.
 * @param ssn Social Security Number
 * @param aliases Known Aliases
 * @param telephoneNumber Telephone Number
 * @param email Email Address
 * @param trackingCode Tracking code for Web analytics
 * @param uuid An Universally Unique Identifier
 */
@Deprecated
public record Person(
    @Valid @NotNull Name name,
    @NotNull @Min(0) @Max(100) Integer age,
    @NotNull GenderEnum gender,
    @NotNull @DecimalMin("0") BigDecimal height,
    @Valid Person legalGuardian,
    @NotNull @Pattern(regexp = "^\\d{3}-\\d{2}-\\d{4}$") String ssn,
    @NotNull @Size(min = 1, max = 3) Set<String> aliases,
    String telephoneNumber,
    @NotNull @Email String email,
    @NotNull @Size(min = 5, max = 50) String trackingCode,
    @NotNull UUID uuid) {

  public Person(
      final Name name,
      final Integer age,
      final GenderEnum gender,
      final BigDecimal height,
      final Person legalGuardian,
      final String ssn,
      final Set<String> aliases,
      final String telephoneNumber,
      final String email,
      final String trackingCode,
      final UUID uuid) {
    this.name = name;
    this.age = age;
    this.gender = gender;
    this.height = height;
    this.legalGuardian = legalGuardian;
    this.ssn = ssn;
    this.aliases = Objects.requireNonNullElseGet(aliases, () -> new LinkedHashSet<>());
    this.telephoneNumber = telephoneNumber;
    this.email = email;
    this.trackingCode = Objects.requireNonNullElse(trackingCode, "utm_source=default");
    this.uuid = uuid;
  }

  /**
   * Gender
   */
  public enum GenderEnum {
    MALE("Male"),
    FEMALE("Female");

    private final String value;

    GenderEnum(final String value) {
      this.value = value;
    }

    /**
     * Gets the {@code value} of this enum.
     *
     * @return the value of this enum.
     */
    public String getValue() {
      return value;
    }

    /**
     * Case-sensitively matches the given {@code value} to an enum constant using {@link
     * #getValue()}.
     *
     * <p><b>NOTE:</b> if multiple enum constants have a matching value, the first enum constant is
     * returned, by the order they are declared.
     *
     * @param value of the enum.
     * @return a {@link GenderEnum } with the matching value.
     * @throws IllegalArgumentException if no enum has a value matching the given value.
     */
    public static GenderEnum fromValue(final String value) {
      for (final GenderEnum constant : GenderEnum.values()) {
        if (constant.getValue().equals(value)) {
          return constant;
        }
      }
      throw new IllegalArgumentException("Unexpected value '" + value + "'");
    }
  }
}

Further examples

Refer to the test-cases for generated classes, as these list supported plugin <configuration>-options and OpenAPI Specification-properties. The unit-tests could clarify expected behaviors, and the OpenAPI Specification could also provide concrete examples and use-cases. For reference:

Encountered an issue?

Firstly, make a minimal reproducible example - it will greatly facilitate troubleshooting!

Please, verify these steps without custom mustache-template files:

  1. Verify that the Maven Build Configuration is correct.
  2. Verify that the OpenAPI Specification is valid.
  3. Verify that classes are generated successfully.
  4. Verify that needed dependencies are imported.

Once verified, use the custom mustache-template files and verify the following:

  1. Verify that the openapi-generator-maven-plugin configuration options are supported. See Supported ‘openapi‐generator‐maven‐plugin’ Configuration options.
    • If no configuration options are set, please proceed to the next step.
    • If the configuration option is not listed as supported - please request it via open an issue.
  2. Verify that the OpenAPI Specification properties are supported. See Supported OpenAPI Specification properties.
    • If the property is not listed as supported - please request it via open an issue.
  3. Compare openapi-generator-maven-plugin versions
    • As a last resort, it could be due to using an older/newer version than what is used within this project for testing. Even if this would solve the issue - please report it via open an issue.

If problems persist, check the open issues. If the problem you are facing has not already been reported, please open an issue with details and instructions to reproduce.

Useful Resources