Understanding MicroProfile OpenAPI Specification 3.0
This article explains the MicroProfile OpenAPI 3.0 specification, covering its architecture, configuration options, core properties, annotation usage, server definitions, programming model, model readers, filters, processing rules, endpoint behavior, and release notes for both 3.0 and earlier versions.
Overview
MicroProfile OpenAPI 1.0 defines Java interfaces and a programming model that generate OpenAPI v3 documentation directly from JAX‑RS applications. The specification relies on MicroProfile Config for all configuration values.
Core Configuration Properties
mp.openapi.model.reader– Fully qualified class name of an OASModelReader implementation. mp.openapi.filter – Fully qualified class name of an OASFilter implementation. mp.openapi.scan.disable – Boolean flag to disable annotation scanning (default false). mp.openapi.scan.packages – Comma‑separated list of packages to scan (e.g., mp.openapi.scan.packages=com.xyz.A,com.xyz.B). mp.openapi.scan.classes – Comma‑separated list of classes to scan. mp.openapi.scan.exclude.packages – Packages to exclude from scanning. mp.openapi.scan.exclude.classes – Classes to exclude from scanning. mp.openapi.servers – Global server list (e.g.,
mp.openapi.servers=https://api.example.com/v1,https://backup.example.com/v1). mp.openapi.servers.path. – Prefix for path‑specific server overrides. mp.openapi.servers.operation. – Prefix for operation‑specific server overrides (requires an operationId). mp.openapi.schema. – JSON‑encoded schema definitions for specific classes when source code is unavailable.
Example Schema Configuration
mp.openapi.schema.java.util.Date = {</code>
<code> "name": "EpochMillis",</code>
<code> "type": "number",</code>
<code> "format": "int64",</code>
<code> "description": "Milliseconds since 1970‑01‑01T00:00:00Z"</code>
<code>}Documentation Mechanisms
Enhance JAX‑RS annotations with OpenAPI annotations.
Start from the initial /openapi output and augment it with static OpenAPI files (contract‑first).
Provide a programmatic model tree via the programming model.
Apply filters after the document is built to modify or remove elements.
Annotation Priority
If the same annotation appears on both a class and a method, the method value overrides the class value (common for @Server and @Tag). For @Parameter and @RequestBody, method‑parameter annotations override method‑level annotations; mixing them is discouraged.
Key Annotation Examples
Operation with Summary
@GET</code>
<code>@Path("/findByStatus")</code>
<code>@Operation(summary = "Finds Pets by status", description = "Multiple status values can be provided with comma‑separated strings")</code>
<code>public Response findPetsByStatus(...){ ... }Resulting fragment:
/pet/findByStatus:</code>
<code> get:</code>
<code> summary: Finds Pets by status</code>
<code> description: Multiple status values can be provided with comma separated strings</code>
<code> operationId: findPetsByStatusOperation with Multiple Responses
@GET</code>
<code>@Path("/{username}")</code>
<code>@Operation(summary = "Get user by user name")</code>
<code>@APIResponse(description = "The user", content = @Content(mediaType = "application/json", schema = @Schema(implementation = User.class)))</code>
<code>@APIResponse(responseCode = "400", description = "User not found")</code>
<code>public Response getUserByName(@Parameter(description = "The name that needs to be fetched. Use user1 for testing.", required = true) @PathParam("username") String username){...} /user/{username}:</code>
<code> get:</code>
<code> summary: Get user by user name</code>
<code> operationId: getUserByName</code>
<code> parameters:</code>
<code> - name: username</code>
<code> in: path</code>
<code> description: "The name that needs to be fetched. Use user1 for testing."
<code> required: true</code>
<code> schema:</code>
<code> type: string</code>
<code> responses:</code>
<code> default:</code>
<code> description: The user</code>
<code> content:</code>
<code> application/json:</code>
<code> schema:</code>
<code> $ref: '#/components/schemas/User'</code>
<code> 400:</code>
<code> description: User not foundRequest Body Example
@POST</code>
<code>@Path("/user")</code>
<code>@Operation(summary = "Create user", description = "This can only be done by the logged in user.")</code>
<code>public Response createUser(@RequestBody(description = "Created user object", required = true, content = @Content(schema = @Schema(implementation = User.class))) User user, @QueryParam("name") String name, @QueryParam("code") String code){ ... } post:</code>
<code> summary: Create user</code>
<code> description: This can only be done by the logged in user.</code>
<code> operationId: createUser</code>
<code> parameters:</code>
<code> - name: name</code>
<code> in: query</code>
<code> schema:</code>
<code> type: string</code>
<code> - name: code</code>
<code> in: query</code>
<code> schema:</code>
<code> type: string</code>
<code> requestBody:</code>
<code> description: Created user object</code>
<code> content:</code>
<code> '*/*':</code>
<code> schema:</code>
<code> $ref: '#/components/schemas/User'</code>
<code> required: true</code>
<code> responses:</code>
<code> default:</code>
<code> description: no descriptionServer Definition Precedence
Servers can be defined globally, per‑path, or per‑operation. Method‑level @Server entries override class‑level entries, which in turn override definition‑level entries.
@OpenAPIDefinition(servers = { @Server(description = "definition server", url = "http://{var1}.def/{var2}", variables = { @ServerVariable(name = "var1", defaultValue = "1", enumeration = {"1","2"}), @ServerVariable(name = "var2", defaultValue = "1", enumeration = {"1","2"}) }) })</code>
<code>@Server(description = "class server", url = "http://{var1}.class/{var2}")</code>
<code>public class ServersResource {</code>
<code> @GET @Path("/")</code>
<code> @Server(description = "method server", url = "http://{var1}.method")</code>
<code> public Response get(){ return Response.ok("ok").build(); }</code>
<code>} openapi: 3.0.2</code>
<code>servers:</code>
<code>- url: http://{var1}.def/{var2}</code>
<code> description: definition server</code>
<code>paths:</code>
<code> /:</code>
<code> get:</code>
<code> operationId: get</code>
<code> servers:</code>
<code> - url: http://{var1}.class/{var2}</code>
<code> description: class server</code>
<code> - url: http://{var1}.method</code>
<code> description: method serverProgramming Model
Model objects are created via OASFactory in the org.eclipse.microprofile.openapi.models package.
OASFactory.createObject(Info.class)</code>
<code> .title("Airlines")</code>
<code> .description("Airlines APIs")</code>
<code> .version("1.0.0");OASModelReader
Implement OASModelReader to supply a complete or partial OpenAPI model tree. Register it with mp.openapi.model.reader (e.g., mp.openapi.model.reader=com.mypkg.MyReader). If a full model is supplied, set mp.openapi.scan.disable=true to skip annotation scanning.
OASFilter
Implement OASFilter to receive callbacks for each OpenAPI element and modify or remove them. Register with mp.openapi.filter (e.g., mp.openapi.filter=com.mypkg.MyFilter). Child elements are processed before their parents; filterOpenAPI is called last.
Processing Rules
Read configuration values from the mp.openapi namespace.
Invoke the registered OASModelReader (if any).
Load a static OpenAPI file from the application’s META-INF directory (named openapi.yml, openapi.yaml or openapi.json).
Process JAX‑RS and OpenAPI annotations unless scanning is disabled.
Apply all registered OASFilter implementations.
The later steps override values from earlier steps.
OpenAPI Endpoint
The fully processed document is exposed at the root URL /openapi via HTTP GET. The default response format is YAML; if the request contains Accept: application/json, the implementation must return JSON with Content‑Type: application/json. Implementations may optionally support a format query parameter to switch between YAML and JSON.
Root Prefix Handling
If an application is deployed under a root prefix (e.g., /myApp), server URLs must include that prefix or the corresponding proxy URL.
Multiple Applications
When a MicroProfile runtime hosts multiple applications, the /openapi endpoint should return the logical union of all generated OpenAPI documents, handling ID conflicts and ensuring unique naming.
Integration with Other MicroProfile Specs
Interfaces annotated with @RegisterRestClient are excluded from the generated OpenAPI document, preventing internal client contracts from leaking into the public API description.
Release Notes – MicroProfile OpenAPI 3.0
API/SPI Changes
Model interfaces no longer extend Map; explicit methods are provided for Scopes, ServerVariables, APIResponses, Callback, Content, Path, SecurityRequirement, Server, PathItem, and Schema.
New annotations: @SchemaProperty, @RequestBodySchema, @APIResponseSchema.
Configuration property mp.openapi.schema.* allows defining schemas for classes without source code.
Feature Changes
Getter methods now return copies of internal collections; setters must not store the passed collection directly, improving immutability and thread safety.
Other Changes
JavaDoc updated, TCK enhanced to verify new behavior, numerous minor bug fixes and documentation improvements.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JakartaEE China Community
JakartaEE China Community, official website: jakarta.ee/zh/community/china; gitee.com/jakarta-ee-china; space.bilibili.com/518946941; reply "Join group" to get QR code
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
