This page consolidates Grimm’s public surface: artefacts to declare, exported Java modules, OpenAPI 3.1 annotations the scanner understands, and mp.openapi.* keys honoured by ConfigApplier.
Maven artefacts
groupId |
artifactId |
Role |
|---|---|---|
|
|
Annotation scanner, JSON/YAML serializer, internal model, merger, |
|
|
APT processor generating the |
|
|
Vauban BCE, |
|
|
JMH benchmarks (vs SmallRye). Not for production. |
|
|
Standalone or integrated usage examples. |
|
|
Official MP OpenAPI 4.2 TCK runner — out of reactor (Model 4.0.0). Do not declare as an application dependency. |
Every artefact is at 0.4.0-SNAPSHOT.
Java modules
NEW Every Grimm jar ships its compiled module-info.class, so Grimm is made of the three named modules below, never of automatic modules. Up to 0.3.0 the descriptors were not compiled into the jars: Grimm ran as automatic modules (grimm.core, grimm.processor, grimm.cdi.vauban), and in a modular application a build tool could take grimm-cdi-vauban for a class-path jar and split its package (grimm#15). An application module that read Grimm by its automatic name moves to requires io.vidocq.grimm.cdi.vauban; — see Upgrading from 0.3.0.
| Module | Contents |
|---|---|
|
Exports |
|
No exports — the APT processor is consumed exclusively through the |
|
|
Apart from io.vidocq.grimm.internal.reader, the io.vidocq.grimm.internal.* packages are reserved for Grimm’s own modules. Any application class depending on them signals a regression to fix.
Supported MicroProfile OpenAPI annotations
| Annotation | Effect | Status |
|---|---|---|
|
Root metadata ( |
✅ |
|
Describes a JAX-RS method: summary, description, |
✅ |
|
Describes a parameter ( |
✅ |
|
Describes the request body: content, schema, examples. |
✅ |
|
Describes possible responses, code by code, with headers and links. |
✅ |
|
Describes a type: title, description, constraints, |
✅ |
|
Security schemes (HTTP, API Key, OAuth2, OpenID Connect) and requirements. |
✅ |
|
Target URL(s) inscribed on the document, operation, or path. |
✅ |
|
Logical grouping of operations. |
✅ |
|
Server-described webhooks. |
✅ |
|
Free-form |
✅ |
|
Link to external documentation. On a resource method, it becomes the operation’s |
✅ |
|
Describes a response or encoding header, including its |
✅ |
|
Describes one property inside |
✅ |
|
Explicit reuse catalogue. |
✅ |
|
Hides a type, property, or operation from the document — MP OpenAPI has no standalone |
✅ |
JAX-RS annotations consumed by the scanner: @Path, @GET, @POST, @PUT, @DELETE, @PATCH, @HEAD, @OPTIONS, @Produces, @Consumes, @PathParam, @QueryParam, @HeaderParam, @CookieParam, @FormParam, @MatrixParam, @DefaultValue, @ApplicationPath.
How annotation values are mapped NEW
These rules follow the MicroProfile OpenAPI 4.2 Javadoc of each attribute.
-
@Schemaand@SchemaPropertymap the same attributes. Every attribute the two annotations share is applied by one mapping: bounds and their exclusive forms,multipleOf, lengths,pattern, item and property counts,requiredProperties,nullable,readOnly,writeOnly,deprecated,enumeration,defaultValue,constValue,examples,externalDocs(with its extensions), composition (allOf,anyOf,oneOf,not), the discriminator, and the JSON Schema 2020-12 keywords (if/then/else,contains,prefixItems,patternProperties,propertyNames,dependentSchemas,contentSchema, …). When a field’s@Schemaand the class’s@Schema(properties = @SchemaProperty(…))both describe a property, the@SchemaPropertyis applied last, attribute by attribute. -
An attribute left at its default writes nothing. A schema no longer carries
minItems: 2147483647,maxItems: -2147483648ormaxProperties: 0because some other attribute was set; an explicit value,0included, is written. -
A partial
@Schemacounts. On a parameter, a request body, a header or a content entry, a@Schemathat sets any attribute (onlyminimum, onlyexamples, onlyoneOf, …) is applied on top of the inferred schema. An empty@Schema()still gives the inferred schema. -
constValueandexamplesare JSON unless the type isSTRING. Withtype = STRINGthe value is the literal string; with any other type it is parsed as JSON, so@Schema(type = INTEGER, examples = "1")gives the number1and an object example is an object. A value that is not valid JSON stays the string as written. The deprecatedexampleattribute is always copied as written. -
@Extension(parseValue = true)uses a strict JSON reader — the reader of static files.null,1e3, escaped quotes and nested arrays come out as JSON says. Lenient forms that are not JSON ({a: 1}, single quotes,TRUE,1L) stay strings, and a JSONnulladds no extension. -
@DigitsgivesmultipleOforpattern(MicroProfile OpenAPI 4.2), whenmp.openapi.scan.beanvalidationis notfalse:multipleOfof10^-fractionon anumberschema, apatternsuch as^-?\d{1,5}(\.\d{1,2})?$on astringschema, nothing on anintegerschema. A value set explicitly on the schema is never overridden. Decimal values are written as plain decimals in JSON and YAML (0.0000000001, not1E-10), so a YAML 1.1 parser still reads them as numbers. -
A
@DiscriminatorMappingor@PatternPropertywith noschema(left atVoid.class) is skipped instead of producing an empty entry.
Static documents and schema overrides NEW
A static file (META-INF/openapi.yaml, .yml, .json), the value of an mp.openapi.schema.<FQCN> key and the $$GrimmModel fragments of the annotation processor are all read by the same mapper.
-
Standard keywords get their model type.
minimum,maxLength,not,discriminator,xml,externalDocs,allOf, … become typedSchemaproperties, nested schemas included, andtrue/falsesubschemas become boolean schemas. They are no longer stored as extensions, so anOASFilterthat clears a schema’s extensions keeps them. A value of another JSON type is kept as written, for an alternative dialect. -
Unknown keywords are extensions (MicroProfile OpenAPI 4.2). A
Schemakeeps any property it does not know,x-or not, and writes it back.Schema.getAll()lists every property set, standard ones and$refincluded, under its JSON name, andSchema.setAll(…)clears them all before setting the new ones, as the 4.2 Javadoc says. -
$refis kept as written on schemas and on the referenceable objects — parameters, request bodies and responses (whose$refused to be dropped), callbacks (whose$refused to be read as a callback expression), path items: a document reference such asPet.yamlis not expanded into#/components/…, in the static file and when models merge. -
Every field is read. A parameter keeps
style,explode,allowReserved,deprecated,allowEmptyValue,example,examplesandcontent; a header keepsstyle,explode,content,exampleandexamples; a discriminator keeps itsx-keys.type: "null"(alone or in a type array) isSchemaType.NULL, and a type name that is not a JSON Schema type is kept as written. -
YAML numbers follow YAML 1.2:
+1,1e3,.5,0o17and0x1Fare numbers; integers beyond alongare read asBigInteger. -
In
mp.openapi.schema.<FQCN>, the historicalrefkey is accepted at every level of the schema,$defsanddefinitionsincluded, and expands a short name to#/components/schemas/<name>. An explicit$refis kept as written, as in a static file.
MicroProfile Config keys
All keys are read once at startup: GrimmConfigProducer (in io.vidocq.grimm.cdi) calls ConfigProvider.getConfig() and materialises the GrimmConfig record (io.vidocq.grimm.internal.config); ConfigApplier then applies the server and schema overrides at step 5 of the pipeline.
| Key | Effect |
|---|---|
|
Boolean. Disables annotation scanning entirely. |
|
List of packages to scan (whitelist, comma-separated). |
|
List of classes to scan (whitelist). |
|
List of excluded packages. |
|
List of excluded classes. |
|
Boolean. Enables derivation of Bean Validation constraints into the schema. |
|
FQCN of an |
|
FQCN of an |
|
List of server URLs (replaces |
|
Overrides |
|
Overrides |
|
JSON snippet describing a schema for the given class (full override). |
|
Boolean. Disables scanning of |
|
Two spec keys are deliberately deferred and currently unimplemented: |
/openapi endpoint
Path |
|
Verb |
|
Media types |
|
Format override |
|
Source |
|
Status |
Always |
Other CDI containers NEW
Grimm does not need Vauban. The jars run unchanged under another CDI container, and two integration-test modules, grouped under grimm-it-other-containers, prove it on every build (grimm#22):
| Module | What it runs |
|---|---|
|
Weld SE 6.0 (CDI 4.1), class path, no Vauban: the document lists a resource, its operation and its |
|
A WAR compiled with |
Neither module is published. What they found, now fixed:
-
vauban-apiis a runtime dependency ofgrimm-cdi-vauban, under any container. The Vauban build weaves aprotectedconstructor takingio.vidocq.vauban.api.ProxyLinkinto each normal-scoped bean (GrimmModelCache,OpenApiResource,GrimmAutoDiscovery); a container that cannot load that type cannot load the class, and Weld drops the bean with an INFO message (WELD-000119).vauban-apiholds API types only (13 KB): no Vauban code runs outside Vauban. Its Jakarta CDI dependencies are excluded. -
Each container has its own document — see Internals.
-
A complete document in
annotatedmode — compile the application withgrimm-processor: the resources it describes enter the document even when they are not CDI beans. -
grimm-processorcarries Jakarta REST — it reads the Jakarta REST annotations, and anannotationProcessorPathsentry only resolves its compile and runtime dependencies; the API used to beprovidedthere, so the processor could not load from such an entry.
Grimm’s own classes (io.vidocq.grimm.*) never enter the document, so /openapi does not describe itself: keep your application out of that package.
|
Deploying on an application server
|
Compatibility
-
Java 25 (LTS), Maven 3.9.16.
-
JAX-RS 4.0 (Cassini or any conformant runtime).
-
CDI 4.1 Lite (Vauban) or Lite-compatible — proven on Weld SE 6.0 and Open Liberty (CDI 4.0): see Other CDI containers NEW.
-
No Jakarta EE Full Profile dependency.