This page assumes a Jakarta REST 4.0 application already running on Cassini (or any other compatible JAX-RS runtime). It walks through adding Grimm: dependencies, minimal annotation, first GET /openapi call.

Prerequisites

  • Java 25 (LTS) — Temurin recommended.

  • Maven 3.9.16 — pinned by .sdkmanrc at the Grimm root.

  • A JAX-RS 4.0 application already deployed, with at least one @Path resource.

sdk env
./mvnw -ntp install -DskipTests

Maven dependencies

grimm-core carries the scanner and the serializer. grimm-cdi-vauban adds the BCE and the /openapi endpoint. A standard application declares both and lets the runtime wire the rest.

<dependencies>
    <dependency>
        <groupId>io.vidocq.grimm</groupId>
        <artifactId>grimm-core</artifactId>
        <version>0.1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>io.vidocq.grimm</groupId>
        <artifactId>grimm-cdi-vauban</artifactId>
        <version>0.1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.microprofile.openapi</groupId>
        <artifactId>microprofile-openapi-api</artifactId>
        <version>4.1</version>
    </dependency>
</dependencies>

microprofile-openapi-api is provided inside grimm-core but should be declared compile in the application — it provides the annotations the application uses.

Root annotation on the Application class

The @OpenAPIDefinition annotation on the JAX-RS Application class supplies the document’s title, version, and license.

package io.example;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;
import org.eclipse.microprofile.openapi.annotations.OpenAPIDefinition;
import org.eclipse.microprofile.openapi.annotations.info.Info;
import org.eclipse.microprofile.openapi.annotations.info.License;

@ApplicationPath("/api")
@OpenAPIDefinition(
    info = @Info(
        title = "Pet Store API",
        version = "1.0.0",
        license = @License(name = "Apache 2.0", url = "https://www.apache.org/licenses/LICENSE-2.0")
    )
)
public class PetStoreApp extends Application { }

Annotated JAX-RS resource

A minimal JAX-RS resource, enriched with @Operation and @Schema to describe the operation.

package io.example;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.media.Schema;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;

@Path("/pets")
@ApplicationScoped
public class PetResource {

    @GET
    @Path("/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    @Operation(summary = "Find a pet by identifier")
    public Pet find(
        @Parameter(description = "Unique identifier", required = true)
        @PathParam("id") long id) {
        return new Pet(id, "Rex");
    }

    @Schema(name = "Pet", description = "A pet in the registry")
    public record Pet(long id, String name) { }
}

Calling /openapi

At startup, the GrimmExtension BCE scans the classpath, merges sources, and publishes the document. No additional application code is required.

# YAML — default format, MP OpenAPI 4.1 §2.2
curl http://localhost:8080/openapi

# JSON via Accept
curl -H "Accept: application/json" http://localhost:8080/openapi

# JSON via query override (spec §2.3, prioritized over Accept)
curl http://localhost:8080/openapi?format=json

The YAML output looks like:

openapi: 3.1.0
info:
  title: Pet Store API
  version: 1.0.0
  license:
    name: Apache 2.0
    url: https://www.apache.org/licenses/LICENSE-2.0
paths:
  /api/pets/{id}:
    get:
      summary: Find a pet by identifier
      parameters:
        - name: id
          in: path
          required: true
          description: Unique identifier
          schema:
            type: integer
            format: int64
      responses:
        "200":
          description: OK
components:
  schemas:
    Pet:
      type: object
      description: A pet in the registry
      properties:
        id:
          type: integer
          format: int64
        name:
          type: string

Three combinable sources

Grimm merges up to three sources of truth:

Source Description Activation

Annotations

Scan of @Path classes in the current CDI module.

Automatic, default.

Static document

META-INF/openapi.yaml, .yml or .json packaged in the classpath.

The file’s mere presence suffices.

OASModelReader

Java class building an OpenAPI programmatically.

mp.openapi.model.reader=fqn.ModelReader.

Priority order is defined by the MP OpenAPI 4.1 spec: OASModelReader < static < annotations < OASFilter. See Concepts for the detailed mechanics.

Next step

  • Usage patterns — pagination, polymorphism, security, callbacks.

  • Concepts — OpenAPI model, merge, filters.

  • Reference — supported annotations, mp.openapi.* keys.