Java annotations for defining Swagger API documentation and OpenAPI specification metadata
—
Annotations for adding custom extensions and examples to Swagger specifications. The extension system allows you to add vendor-specific or custom metadata to any Swagger element, while example annotations provide sample data for better API documentation and testing.
Defines custom extensions for Swagger specification elements. Extensions allow you to add vendor-specific or custom metadata that extends beyond the standard Swagger specification. All extension names are automatically prefixed with "x-" to follow OpenAPI conventions.
/**
* Defines custom extensions for Swagger specification
* Target: ANNOTATION_TYPE
* Retention: RUNTIME
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Extension {
/**
* Name of the extension
* Will be prefixed with "x-" automatically in the generated specification
* Use descriptive names that indicate the extension's purpose
*/
String name() default "";
/**
* Array of name/value pairs for the extension
* Contains the actual extension data as key-value properties
* REQUIRED ATTRIBUTE
*/
ExtensionProperty[] properties();
}Usage Examples:
// Simple extension with single property
@ApiOperation(
value = "Get user profile",
extensions = {
@Extension(
name = "code-samples",
properties = {
@ExtensionProperty(name = "javascript", value = "fetch('/users/123')")
}
)
}
)
@GET
@Path("/{id}")
public User getUser(@PathParam("id") Long id) {
// implementation
}
// Multiple extensions on model property
public class Product {
@ApiModelProperty(
value = "Product price in cents",
example = "1299",
extensions = {
@Extension(
name = "validation",
properties = {
@ExtensionProperty(name = "min", value = "0"),
@ExtensionProperty(name = "max", value = "999999"),
@ExtensionProperty(name = "currency", value = "USD")
}
),
@Extension(
name = "display",
properties = {
@ExtensionProperty(name = "format", value = "currency"),
@ExtensionProperty(name = "symbol", value = "$")
}
)
}
)
private Integer price;
}
// Extension with JSON parsing
@ApiOperation(
value = "Create order",
extensions = {
@Extension(
name = "workflow",
properties = {
@ExtensionProperty(
name = "steps",
value = "[\"validate\", \"process\", \"fulfill\", \"notify\"]",
parseValue = true // Parse as JSON array
)
}
)
}
)
@POST
public Order createOrder(CreateOrderRequest request) {
// implementation
}
// Vendor-specific extensions
@ApiModelProperty(
value = "Customer ID",
extensions = {
@Extension(
name = "amazon-integration",
properties = {
@ExtensionProperty(name = "marketplace-id", value = "A1PA6795UKMFR9"),
@ExtensionProperty(name = "seller-id", value = "A2EXAMPLE123")
}
),
@Extension(
name = "analytics",
properties = {
@ExtensionProperty(name = "track-conversions", value = "true"),
@ExtensionProperty(name = "segment", value = "premium-customers")
}
)
}
)
private String customerId;Defines name/value pairs within extensions. Each property represents a key-value pair of metadata that gets added to the extension object in the generated Swagger specification.
/**
* Defines name/value pairs within extensions
* Target: ANNOTATION_TYPE
* Retention: RUNTIME
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ExtensionProperty {
/**
* Property name within the extension
* Used as the key in the extension object
* REQUIRED ATTRIBUTE
*/
String name();
/**
* Property value within the extension
* Can be any string value or JSON when parseValue is true
* REQUIRED ATTRIBUTE
*/
String value();
/**
* Whether to parse the value as JSON/YAML
* When true, the value string is parsed as structured data
* When false (default), the value is treated as a literal string
*/
boolean parseValue() default false;
}Usage Examples:
// String properties
@Extension(
name = "security",
properties = {
@ExtensionProperty(name = "classification", value = "confidential"),
@ExtensionProperty(name = "data-owner", value = "finance-team"),
@ExtensionProperty(name = "retention-period", value = "7-years")
}
)
// Numeric and boolean properties
@Extension(
name = "rate-limiting",
properties = {
@ExtensionProperty(name = "requests-per-minute", value = "100"),
@ExtensionProperty(name = "burst-limit", value = "20"),
@ExtensionProperty(name = "enabled", value = "true")
}
)
// JSON object properties
@Extension(
name = "client-config",
properties = {
@ExtensionProperty(
name = "timeout-settings",
value = "{\"connect\": 5000, \"read\": 30000, \"total\": 35000}",
parseValue = true
),
@ExtensionProperty(
name = "retry-policy",
value = "{\"maxAttempts\": 3, \"backoffMs\": 1000, \"exponential\": true}",
parseValue = true
)
}
)
// Array properties
@Extension(
name = "allowed-origins",
properties = {
@ExtensionProperty(
name = "domains",
value = "[\"https://app.example.com\", \"https://admin.example.com\"]",
parseValue = true
)
}
)
// Complex nested structure
@Extension(
name = "monitoring",
properties = {
@ExtensionProperty(
name = "metrics",
value = "{" +
"\"enabled\": true, " +
"\"collectors\": [\"prometheus\", \"datadog\"], " +
"\"sampling\": {\"rate\": 0.1, \"max-traces\": 1000}" +
"}",
parseValue = true
)
}
)Container for multiple example properties, used to provide sample data for request/response bodies. Examples help API consumers understand the expected data format and structure.
/**
* Container for multiple example properties
* Target: ANNOTATION_TYPE
* Retention: RUNTIME
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Example {
/**
* Array of example properties
* Each property defines an example for a specific media type
* REQUIRED ATTRIBUTE
*/
ExampleProperty[] value();
}Usage Examples:
// Examples for request body
@ApiOperation(value = "Create user account")
@ApiParam(
value = "User registration data",
examples = @Example({
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"username\": \"johndoe\"," +
"\"email\": \"john@example.com\"," +
"\"firstName\": \"John\"," +
"\"lastName\": \"Doe\"" +
"}"
),
@ExampleProperty(
mediaType = "application/xml",
value = "<user>" +
"<username>johndoe</username>" +
"<email>john@example.com</email>" +
"<firstName>John</firstName>" +
"<lastName>Doe</lastName>" +
"</user>"
)
})
)
@POST
public User createUser(UserRegistrationRequest request) {
// implementation
}
// Response examples
@ApiResponse(
code = 200,
message = "Product details retrieved successfully",
response = Product.class,
examples = @Example({
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"id\": 12345," +
"\"name\": \"Wireless Headphones\"," +
"\"description\": \"High-quality wireless headphones with noise cancellation\"," +
"\"price\": 199.99," +
"\"category\": \"Electronics\"," +
"\"inStock\": true," +
"\"tags\": [\"audio\", \"wireless\", \"noise-cancelling\"]" +
"}"
)
})
)
@GET
@Path("/{id}")
public Product getProduct(@PathParam("id") Long id) {
// implementation
}
// Multiple examples for different scenarios
@ApiParam(
value = "Order data",
examples = @Example({
// Minimal order example
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"customerId\": \"cust_123\"," +
"\"items\": [{\"productId\": \"prod_456\", \"quantity\": 1}]" +
"}"
),
// Complete order example with all fields
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"customerId\": \"cust_123\"," +
"\"items\": [" +
"{\"productId\": \"prod_456\", \"quantity\": 2, \"price\": 29.99}," +
"{\"productId\": \"prod_789\", \"quantity\": 1, \"price\": 15.50}" +
"]," +
"\"shippingAddress\": {" +
"\"street\": \"123 Main St\"," +
"\"city\": \"Anytown\"," +
"\"zipCode\": \"12345\"," +
"\"country\": \"US\"" +
"}," +
"\"paymentMethod\": \"credit_card\"," +
"\"notes\": \"Please leave at front door\"" +
"}"
)
})
)
@POST
@Path("/orders")
public Order createOrder(CreateOrderRequest request) {
// implementation
}Defines media type and example value pairs. Each property associates a specific example with a media type, allowing different examples for different content types.
/**
* Defines media type and example value pairs
* Target: ANNOTATION_TYPE
* Retention: RUNTIME
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ExampleProperty {
/**
* Media type for this example
* Specifies the content type this example applies to
* Common values: "application/json", "application/xml", "text/plain"
*/
String mediaType() default "";
/**
* Example value for the specified media type
* Should be a valid representation in the specified media type format
* REQUIRED ATTRIBUTE
*/
String value();
}Usage Examples:
// JSON examples
@ExampleProperty(
mediaType = "application/json",
value = "{\"message\": \"Hello, World!\"}"
)
// XML examples
@ExampleProperty(
mediaType = "application/xml",
value = "<message>Hello, World!</message>"
)
// Plain text examples
@ExampleProperty(
mediaType = "text/plain",
value = "Hello, World!"
)
// CSV examples
@ExampleProperty(
mediaType = "text/csv",
value = "id,name,email\n1,John Doe,john@example.com\n2,Jane Smith,jane@example.com"
)
// Complex JSON structures
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"user\": {" +
"\"id\": 123," +
"\"profile\": {" +
"\"name\": \"John Doe\"," +
"\"preferences\": {" +
"\"theme\": \"dark\"," +
"\"notifications\": true," +
"\"languages\": [\"en\", \"es\"]" +
"}" +
"}" +
"}," +
"\"metadata\": {" +
"\"created\": \"2023-01-15T10:30:00Z\"," +
"\"lastUpdated\": \"2023-12-01T14:22:33Z\"" +
"}" +
"}"
)
// Error response examples
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"error\": {" +
"\"code\": \"VALIDATION_FAILED\"," +
"\"message\": \"The request contains invalid data\"," +
"\"details\": [" +
"{\"field\": \"email\", \"message\": \"Invalid email format\"}," +
"{\"field\": \"age\", \"message\": \"Age must be between 13 and 120\"}" +
"]" +
"}" +
"}"
)Here's a comprehensive example showing how all extension and example annotations work together:
@Api(tags = "orders")
@Path("/orders")
public class OrderController {
@ApiOperation(
value = "Create a new order",
notes = "Creates a new order with the provided details. Supports both simple and complex order structures.",
response = Order.class,
code = 201,
extensions = {
@Extension(
name = "workflow",
properties = {
@ExtensionProperty(name = "type", value = "async"),
@ExtensionProperty(name = "estimated-duration", value = "2-5 seconds"),
@ExtensionProperty(
name = "steps",
value = "[\"validate\", \"inventory-check\", \"payment-process\", \"fulfill\"]",
parseValue = true
)
}
),
@Extension(
name = "rate-limiting",
properties = {
@ExtensionProperty(name = "per-minute", value = "10"),
@ExtensionProperty(name = "per-hour", value = "100"),
@ExtensionProperty(name = "burst-allowance", value = "5")
}
)
}
)
@ApiResponses({
@ApiResponse(
code = 201,
message = "Order created successfully",
response = Order.class,
examples = @Example({
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"id\": \"ord_1234567890\"," +
"\"status\": \"pending\"," +
"\"customerId\": \"cust_123\"," +
"\"total\": 75.48," +
"\"currency\": \"USD\"," +
"\"createdAt\": \"2023-12-01T10:30:00Z\"," +
"\"items\": [" +
"{\"productId\": \"prod_456\", \"quantity\": 2, \"unitPrice\": 29.99}," +
"{\"productId\": \"prod_789\", \"quantity\": 1, \"unitPrice\": 15.50}" +
"]" +
"}"
)
})
),
@ApiResponse(
code = 400,
message = "Invalid order data",
examples = @Example({
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"error\": {" +
"\"code\": \"INVALID_ORDER_DATA\"," +
"\"message\": \"The order contains invalid information\"," +
"\"details\": [" +
"{\"field\": \"customerId\", \"message\": \"Customer ID is required\"}," +
"{\"field\": \"items[0].quantity\", \"message\": \"Quantity must be positive\"}" +
"]" +
"}" +
"}"
)
})
)
})
@POST
public Response createOrder(
@ApiParam(
value = "Order creation request",
required = true,
examples = @Example({
// Simple order example
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"customerId\": \"cust_123\"," +
"\"items\": [" +
"{\"productId\": \"prod_456\", \"quantity\": 1}" +
"]" +
"}"
),
// Complex order example
@ExampleProperty(
mediaType = "application/json",
value = "{" +
"\"customerId\": \"cust_123\"," +
"\"items\": [" +
"{\"productId\": \"prod_456\", \"quantity\": 2}," +
"{\"productId\": \"prod_789\", \"quantity\": 1}" +
"]," +
"\"shippingAddress\": {" +
"\"name\": \"John Doe\"," +
"\"street\": \"123 Main St\"," +
"\"city\": \"Springfield\"," +
"\"state\": \"IL\"," +
"\"zipCode\": \"62701\"," +
"\"country\": \"US\"" +
"}," +
"\"billingAddress\": {" +
"\"name\": \"John Doe\"," +
"\"street\": \"123 Main St\"," +
"\"city\": \"Springfield\"," +
"\"state\": \"IL\"," +
"\"zipCode\": \"62701\"," +
"\"country\": \"US\"" +
"}," +
"\"paymentMethod\": {" +
"\"type\": \"credit_card\"," +
"\"cardToken\": \"tok_1234567890\"" +
"}," +
"\"specialInstructions\": \"Please call before delivery\"," +
"\"giftMessage\": \"Happy Birthday!\"," +
"\"expedited\": false" +
"}"
),
// XML format example
@ExampleProperty(
mediaType = "application/xml",
value = "<order>" +
"<customerId>cust_123</customerId>" +
"<items>" +
"<item>" +
"<productId>prod_456</productId>" +
"<quantity>1</quantity>" +
"</item>" +
"</items>" +
"</order>"
)
})
)
CreateOrderRequest orderRequest
) {
// implementation
return Response.status(201).build();
}
}
// Model with extensions and examples
@ApiModel(description = "Order creation request")
public class CreateOrderRequest {
@ApiModelProperty(
value = "Customer identifier",
required = true,
example = "cust_123",
extensions = {
@Extension(
name = "validation",
properties = {
@ExtensionProperty(name = "pattern", value = "^cust_[a-zA-Z0-9]{3,20}$"),
@ExtensionProperty(name = "required", value = "true")
}
),
@Extension(
name = "database",
properties = {
@ExtensionProperty(name = "table", value = "customers"),
@ExtensionProperty(name = "foreign-key", value = "id")
}
)
}
)
private String customerId;
@ApiModelProperty(
value = "List of items to order",
required = true,
extensions = {
@Extension(
name = "constraints",
properties = {
@ExtensionProperty(name = "min-items", value = "1"),
@ExtensionProperty(name = "max-items", value = "50")
}
)
}
)
private List<OrderItem> items;
// getters and setters
}Install with Tessl CLI
npx tessl i tessl/maven-io-swagger--swagger-annotations