-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Swagger 2.X Integration and Configuration
NOTE: Swagger Core 2.X produces OpenApi 3.0 definition files. If you're looking for swagger 1.5.X and OpenApi 2.0, please refer to 1.5.X JAX-RS Setup
This page details integration and configuration of Swagger, please also check out Quick start and annotations
NOTE: Since version 2.2.0 Swagger Core supports OpenAPI 3.1; see this page for details
Since version 2.1.7 Swagger Core supports also Jakarta namespace, with a parallel set of artifacts with -jakarta
suffix, providing the same functionality as the "standard" javax
namespace ones.
While behaviour described in this documentation is the same for both namespaces, artifact IDs, JEE / Jakarta EE versions and Jackson versions mentioned
refer to javax
namespace.
If you are using jakarta namespace:
- when you read artifact IDs in the form:
swagger-*
(e.g.swagger-core
), replace them withswagger-*-jakarta
(e.g.swagger-core-jakarta
) - when you read
javax.*
in package names, replace that withjakarta
(e.gjakarta.ws.rs.GET
) - when JEE / Jakarta EE dependencies are provided in examples, replace their version with Jakarta EE 9 versions.
- When Jackson dependencies are provided in examples, add the
jakarta
classifier for artifacts supporting it. See Jackson release notesJakarta
namespace Swagger Core artifacts need Jackson 2.12+
Swagger uses maven for build and deployment and its artifacts are available at Maven Central. You can use the maven dependencies with any dependency management system that supports maven dependencies such as Maven, Ivy and Gradle. If you're not using Maven, please refer to Not using Maven
In most scenarios, a single dependency to swagger-jaxrs2
added to the project POM (optionally together with the provided configuration) is all that is needed to integrate swagger-core
into a JAX-RS application.
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
As detailed in Quick start a zero config integration can be obtained by adding one more dependency
to swagger-jaxrs2-servlet-initializer
(or swagger-jaxrs2-servlet-initializer-v2
, see below) (a ServletContainerInitializer implementation which resolves JAX-RS resources from servlet classes):
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
or since version 2.1.2
better (see #3412):
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2</artifactId>
<version>2.1.2</version>
</dependency>
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-jaxrs2-servlet-initializer-v2</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
There are however scenarios in which the dependency to swagger-jaxrs2-servlet-initializer
(or swagger-jaxrs2-servlet-initializer-v2
, see above) is not necessary, as Swagger integration mechanism is capable
of identifying resources from the ones configured by the JAX-RS environment, even without swagger specific settings; these include:
- Resources defined via JAX-RS
Application.getClasses()
- see Jersey and RESTEasy samples. - Resources defined e.g. in
resourcePackages
orresourceClasses
init parameters of JAX-RS framework servlet - see Jersey sample
For example, adding io.swagger.v3.jaxrs2.integration.resources
to Jersey 2 container servlet/filter jersey.config.server.provider.packages
init param is by itself sufficient to integrate Swagger and have it scan and expose resolved spec. (in servlet-context-path/openapi.json
or servlet-context-path/openapi.yaml
).
Refer to the samples for examples of dependencies usage in different environment and configuration scenarios.
In scenarios where e.g. you only care about the annotations, or the OpenAPI specification Java implementation (models
)
or one of the other module, you can just add the specific dependency you need, like
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-annotations</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
or
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-models</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
or
<dependencies>
...
<dependency>
<groupId>io.swagger.core.v3</groupId>
<artifactId>swagger-core</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
Swagger provides two out-of-the-box mechanisms to have the resolved OpenAPI definition exposed as an API:
OpenApiResource and AcceptHeaderOpenApiResource are JAX-RS resources exposing the definition via :
-
/openapi.json
(OpenApiResource
) -
/openapi.yaml
(OpenApiResource
) -
/openapi
withAccept
headerapplication/json
orapplication/yaml
(AcceptHeaderOpenApiResource
)
Depending on the JAX-RS environment in use and its setup, in some cases just adding the swagger-jaxrs2
dependency is sufficient to have the above
resources registered by the JAX-RS environment, and the enpoints activated, e.g. this would be true in a Jersey environment with
no resource packages or classes configured. Check out Jersey and
RESTEasy samples for this scenario.
In other cases you might need to register OpenApiResource
, AcceptHeaderOpenApiResource
or both in your JAX-RS environment, for example:
@ApplicationPath("/sample")
public class MyApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
return Stream.of(PetResource.class, OpenApiResource.class, AcceptHeaderOpenApiResource.class).collect(Collectors.toSet());
}
}
Try it out by cloning/downloading the
Jersey or
RESTEasy sample,
and running it with mvn package jetty:run
OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml
(and .json
).
or
@ApplicationPath("/sample")
public class MyApplication extends ResourceConfig {
public MyApplication() {
OpenApiResource openApiResource = new OpenApiResource();
register(openApiResource);
}
}
Try it out by cloning/downloading the
Jersey sample,
and running it with mvn package jetty:run
OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml
(and .json
).
or
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,io.swagger.sample.resource
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
</web-app>
Try it out by cloning/downloading the
Jersey sample,
and running it with mvn package jetty:run
OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml
(and .json
).
If you want to have the definition exposed independently of your APIs, you can use provided OpenApiServlet
configuring e.g. in web descriptor:
<servlet>
<servlet-name>OpenApi</servlet-name>
<servlet-class>io.swagger.v3.jaxrs2.integration.OpenApiServlet</servlet-class>
<init-param>
<param-name>openApi.configuration.resourcePackages</param-name>
<param-value>io.swagger.sample.resource</param-value>
</init-param>
<!-- alternatively include a file openapi.json or openapi.yaml / openapi-configuration.json or openapi-configuration.yaml in classpath -->
<!-- alternatively include a configuration file in the location specified below -->
<!--
<init-param>
<param-name>openApi.configuration.location</param-name>
<param-value>/openapi-configuration.json</param-value>
</init-param>
-->
</servlet>
<servlet-mapping>
<servlet-name>OpenApi</servlet-name>
<url-pattern>/openapi/*</url-pattern>
</servlet-mapping>
Try it out by cloning/downloading the
Jersey sample,
and running it with mvn package jetty:run
OpenAPI definition will be available at http://localhost:8002/openapi/openapi.yaml
(and .json
).
Alternatively you can "custom expose" it either extending BaseOpenApiResource or resolving the definition spec and then exposing it via whatever mechanism suiting your needs.
You can define your own endpoints and/or execute additional logic, by extending BaseOpenApiResource
which provides the logic to load/init
swagger context and resolve the OpenAPI definition, e.g. like:
@Path("/mycustompath")
public class CustomOpenApiResource extends BaseOpenApiResource {
@Context
ServletConfig config;
@Context
Application app;
@GET
@Produces({MediaType.APPLICATION_JSON})
@Operation(hidden = true)
public Response getOpenApi(@Context HttpHeaders headers,
@Context UriInfo uriInfo) throws Exception {
return super.getOpenApi(headers, config, app, uriInfo, "json");
}
}
Notice the @Operation(hidden = true)
annotation, keeping the resource from being included in the resulting definition.
In swagger-core
context, Configuration
is a set of properties which affects the OpenAPI definition outcome by declaring e.g.
the packages to be considered while resolving the definition (resourcePackages
), if want a pretty printed output (prettyPrint
),
the definition cache TTL (cacheTTL
), an OpenAPI definition directly in OpenAPI format, which will be merged with the resolved definition (openAPI
).
Please check out below for the complete set of available properties.
Note that the configuration can also be absent, see Quick start for such a scenario.
There are several ways to provide a configuration, detailed below. probably the easiest and least intrusive way is via a configuration file in YAML or JSON format, however also servlet init parameters, programmatic configuration, service loader options are available.
Probably the simplest and more powerful mechanism to hook and configure Swagger with your application is using a configuration file in YAML or JSON format.
You can either rely on swagger scanning known locations, or provide the location of such file as an init param or programmatically.
A typical example of a configuration file is:
resourcePackages:
- io.swagger.sample.resource
prettyPrint: true
cacheTTL: 0
openAPI:
info:
version: '1.0'
title: Swagger Pet Sample App Config File
description: 'This is a sample server Petstore server. You can find out more
about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,
#swagger](http://swagger.io/irc/). For this sample, you can use the api key
`special-key` to test the authorization filters.'
termsOfService: http://swagger.io/terms/
contact:
email: apiteam@swagger.io
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
In the example above, we are providing the packages to be considered while resolving the definition
(resourcePackages
), we declare we want a pretty printed output (prettyPrint
), we disable the cache to
resolve the definition each time the endpoint is hit (cacheTTL
), and we provide an info section directly in
OpenAPI format, which will be merged with the resolved definition (openAPI
).
Please check out below for the complete set of available properties.
Dropping a file named openapi.yaml
or openapi.json
or openapi-configuration.yaml
or openapi-configuration.json
to a classpath or filesystem location from a specific set
is probably the easiest way to provide a configuration. Depending on the environment, known locations include:
Path | Type | Environment |
---|---|---|
openapi.yaml |
classpath | All |
openapi.json |
classpath | All |
openapi.yaml |
file | All |
openapi.json |
file | All |
openapi.yaml |
servletpath | Web app (root of webapp) |
openapi.json |
servletpath | Web app (root of webapp) |
WEB-INF/openapi.yaml |
servletpath | Web app |
WEB-INF/openapi.json |
servletpath | Web app |
openapi-configuration.yaml |
classpath | All |
openapi-configuration.json |
classpath | All |
openapi-configuration.yaml |
file | All |
openapi-configuration.json |
file | All |
openapi-configuration.yaml |
servletpath | Web app (root of webapp) |
openapi-configuration.json |
servletpath | Web app (root of webapp) |
WEB-INF/openapi-configuration.yaml |
servletpath | Web app |
WEB-INF/openapi-configuration.json |
servletpath | Web app |
Try it out by cloning/downloading the
Jersey or
RESTEasy sample,
and running it with mvn package jetty:run
OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml
(and .json
).
While known locations are handy, you might want to specify the path of your configuration file yourself.
In a servlet based environment, such path can be defined as a servlet init parameter, e.g. in a Jersey environment with deployment descriptor:
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,io.swagger.sample.resource
</param-value>
</init-param>
<init-param>
<param-name>openApi.configuration.location</param-name>
<param-value>openapi-customname-configuration.json</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Alternatively, it can also be defined in code, e.g. in JAX-RS Application
instance constructor (or in a custom bootstrap servlet, a ServletContainerInitializer
implementation, etc..):
@ApplicationPath("/test")
public class MyApplication extends Application {
public MyApplication() {
try {
new JaxrsOpenApiContextBuilder()
.configLocation("/myconfigfile.json")
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
See also Programmatic configuration below.
In such a scenario you can directly define configuration properties as init parameters of the servlet serving your APIs (or any other "Bootstrap" servlet);
For example within a RESTEasy HttpServletDispatcher
servlet:
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>io.swagger.sample.MyApplication</param-value>
</init-param>
<!-- specify resource classes to scan -->
<init-param>
<param-name>openApi.configuration.resourceClasses</param-name>
<param-value>io.swagger.sample.resource.UserResource</param-value>
</init-param>
<!-- specify scanner implementation -->
<init-param>
<param-name>openApi.configuration.scannerClass</param-name>
<param-value>io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner</param-value>
</init-param>
<!-- pretty print -->
<init-param>
<param-name>openApi.configuration.prettyPrint</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
Please check out below for the complete set of available properties and related parameters keys.
Try it out by cloning/downloading the
Jersey or
RESTEasy sample,
and running it with mvn package jetty:run
OpenAPI definition will be available at http://localhost:8002/sample/openapi.yaml
(and .json
).
If for any reason it is preferable to provide a configuration (and initialization) programmatically, you can do it in any "bootstrap" code available, e.g.:
The mechanism applied is the same used to expose the OpenAPI definition, and makes use of contexts.
@ApplicationPath("/sample")
public class MyApplication extends Application {
public MyApplication(@Context ServletConfig servletConfig) {
super();
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App bootstrap code")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder()
.servletConfig(servletConfig)
.application(this)
.openApiConfiguration(oasConfig)
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
public class Bootstrap extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App - independent config exposed by dedicated servlet")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder()
.servletConfig(config)
.openApiConfiguration(oasConfig)
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new ServletException(e.getMessage(), e);
}
}
}
public class MyBootstrap {
...
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App bootstrap code")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder()
//.servletConfig(servletConfig)
//.application(this)
.openApiConfiguration(oasConfig)
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
Alternatively you can provide an implementation of io.swagger.v3.oas.integration.api.OpenAPIConfigBuilder
returning a configuration instance which will be applied to your integration, adding the following file to your META-INF/services
directory, using standard Java service loader mechanism.
File: META-INF/services/io.swagger.v3.oas.integration.api.OpenAPIConfigBuilder
:
foo.bar.YourBuilderImplementationClass
Swagger integration layer makes use of a Configuration and so called contexts to allow for easy integration in different environments,
however use of such contexts
is not necessary to be able to resolve an OpenAPI definition out of a set of JAX-RS resources and related types.
The simplest way to obtain an OpenAPI instance (Java POJO implementing the OpenAPI definition)
is using the Default JAX-RS Reader
:
Reader reader = new Reader(new SwaggerConfiguration());
OpenAPI openAPI = reader.read(MyResourceClass.class);
// or reader.read(Stream.of(MyFirstResourceClass.class, MySecondResourceClass.class).collect(Collectors.toSet()));
You can then further process the OpenAPI POJO e.g serializing it to JSON (Json.prettyPrint(openAPI)
), or to YAML (Yaml.prettyPrint(openAPI)
),
or pass it as entity of the response of your APIs, filtering, modifying, etc.
You can also pass an OpenAPI
instance to the constructor, which will be merged with the resolved one:
Reader reader = new Reader(new OpenAPI().info(new Info().version("2.0")));
OpenAPI openAPI = reader.read(MyResourceClass.class);
Please note that such mechanism to resolve a definition out of a set of resources, can be applied both at design and run time, as long resources are available in classpath.
If you only care about definitions, even not in a JAX-RS environment, you can also directly use swagger-core
converter logic to obtain corresponding
OpenAPI schemas:
final Map<String, Schema> schemas = ModelConverters.getInstance().readAll(cls);
To take full advantage of the configuration options and app environment, context
usage comes handy, allowing to define a Configuration
and/or to pass environment related objects (e.g. servletConfig
, JAX-RS Application
, etc).
An example passing a full configuration (see related Jersey and RESTEasy samples):
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App bootstrap code")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
OpenAPI openAPI = new JaxrsOpenApiContextBuilder()
.openApiConfiguration(oasConfig)
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
or (allowing e.g. to get resource classes from JAX-RS Application
or from servlet init parameters)
try {
OpenAPI openAPI = new JaxrsOpenApiContextBuilder()
.servletConfig(servletConfig)
.application(this)
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
or (passing the path to a file based configuration)
try {
OpenAPI openAPI = new JaxrsOpenApiContextBuilder()
.configLocation("custom-openapi-configuration.yaml")
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
or (if a configuration file is present in a known location)
try {
OpenAPI openAPI = new JaxrsOpenApiContextBuilder()
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
or (if in a Servlet non JAX-RS environment)
try {
OpenAPI openAPI = new ServletOpenApiContextBuilder()
.servletConfig(servletConfig)
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
or (if not in a Web application environment)
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
OpenAPI openAPI = new GenericOpenApiContextBuilder()
.openApiConfiguration(oasConfig)
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
examples above make use of context builders
as a convenient helper to build a context and registering it, handle multiple or root
contexts, etc; you can anyway also use contexts
directly:
OpenApiContext ctx = new XmlWebOpenApiContext()
.servletConfig(servletConfig)
.app(application)
.openApiConfiguration(openApiConfiguration)
.parent(rootCtx)
.init();
ctx.read()
Contexts also allow to register separate instances handling different subsets of the APIs, or different configuration, endpoints etc. This is achieved by
assigning a context id
to a context:
try {
new JaxrsOpenApiContextBuilder()
.ctxId("apiA")
.configLocation("apiA-configuration.yaml")
.buildContext(true);
new JaxrsOpenApiContextBuilder()
.ctxId("apiB")
.configLocation("apiB-configuration.yaml")
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
and use it wherever needed:
try {
OpenAPI openAPI_A = new JaxrsOpenApiContextBuilder()
.ctxId("apiA")
.buildContext(true)
.read();
OpenAPI openAPI_B = new JaxrsOpenApiContextBuilder()
.ctxId("apiB")
.buildContext(true)
.read();
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
By default, in a JAX-RS environment, Swagger identifies the set of resources to be "scanned" using io.swagger.v3.jaxrs2.integration.JaxrsApplicationAndAnnotationScanner
, an OpenApiScanner
implementation
which includes:
- Resources defined by JAX-RS application instance in
classes()
andgetSingleton()
(if existing) - Resources defined in configuration
resourceClasses
orresourcePackages
- Types in classpath annotated with
Path
You can customize resource scanning by providing the class name of the scanner to use in the configuration, e.g.:
<init-param>
<param-name>openApi.configuration.scannerClass</param-name>
<param-value>io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner</param-value>
</init-param>
or (in a file configuration)
{
"scannerClass": "my.custom.Scanner",
"prettyPrint" : true,
"openAPI": {
"info": {
"version": "1.0",
"title": "Swagger Pet Sample App",
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "apiteam@swagger.io"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}
}
}
depending on the environment/context, specifically:
Out of the box, in addition to JaxrsApplicationAndAnnotationScanner
, Swagger provides:
-
Since 2.0.10
io.swagger.v3.jaxrs2.integration.JaxrsApplicationAndResourcePackagesAnnotationScanner
: asJaxrsApplicationAndAnnotationScanner
but not considering resources in classpath ifresourcePackages
is not defined. This behaves asJaxrsApplicationAndAnnotationScanner
in versions up to2.0.6
(see also #3284 and #3283) -
io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner
: asJaxrsApplicationAndAnnotationScanner
but not considering resources defined in JAX-RS application instance. -
io.swagger.v3.jaxrs2.integration.JaxrsApplicationScanner
: only considering resources defined in JAX-RS application instance. -
io.swagger.v3.oas.integration.GenericOpenApiScanner
: only considering resources defined in configurationresourceClasses
orresourcePackages
.
If none of these fits your need, you can provide a custom implementation of OpenApiScanner and declare it with one of the mechanisms detailed above.
The following Configuration properties are supported, and can be represented/provided in different ways, as detailed below.
Property | Data type | Equivalent init param |
---|---|---|
resourcePackages |
Set / Comma separated string | openApi.configuration.resourcePackages |
set of resources packages to be scanned for resources; alternatively in a jersey environment, init param jersey.config.server.provider.packages
is also recognized
Property | Data type | Equivalent init param |
---|---|---|
resourceClasses |
Set / Comma separated string | openApi.configuration.resourceClasses |
set of resources classes to be resolved; alternatively in a jersey environment, init param jersey.config.server.provider.classnames
is also recognized
Property | Data type | Equivalent init param |
---|---|---|
openAPI |
Open API |
Open API instance (e.g in json, yaml or java format) that will be merged with the resolved spec. Typically used to add Info section, or any other meta data.
Property | Data type | Equivalent init param |
---|---|---|
prettyPrint |
true/false | openApi.configuration.prettyPrint |
turns pretty printed spec on / off
Property | Data type | Equivalent init param |
---|---|---|
ignoredRoutes |
Set / Comma separated string |
set of routes which will be ignored while resolving
Property | Data type | Equivalent init param |
---|---|---|
cacheTTL |
Long | openApi.configuration.cacheTTL |
resolved spec cache Time to live in milliseconds, default to -1
which means forever, set to 0 to disable cache
Property | Data type | Equivalent init param |
---|---|---|
filterClass |
String | openApi.configuration.filterClass |
custom implementation of io.swagger.v3.core.filter.OpenAPISpecFilter
, invoked after resolving the spec to filter out or modify parts of the spec.
Property | Data type | Equivalent init param |
---|---|---|
readerClass |
String | openApi.configuration.readerClass |
custom implementation of io.swagger.v3.oas.integration.api.OpenApiReader
Property | Data type | Equivalent init param |
---|---|---|
scannerClass |
String | openApi.configuration.scannerClass |
custom implementation of io.swagger.v3.oas.integration.api.OpenApiScanner
Property | Data type | Equivalent init param |
---|---|---|
readAllResources |
true/false | openApi.configuration.readAllResources |
Default to true
. By setting this flag to false only Operation
annotated methods are considered.
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.0.6 | modelConverterClasses |
Set / Comma separated string | openApi.configuration.modelConverterClasses |
set of custom ModelConverters to be applied.
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.0.6 | objectMapperProcessorClass |
String | openApi.configuration.objectMapperProcessorClass |
implementation of io.swagger.v3.oas.integration.api.ObjectMapperProcessor interface, allowing to customize Jackson object mapper in use.
Since 2.1.6 ObjectMapperProcessor
is now defining 2 more methods processOutputJsonObjectMapper
and processOutputYamlObjectMapper
to customize the "output mapper" used for serialization of resolved output.
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.1.6 | sortOutput |
true/false | openApi.configuration.sortOutput |
see https://github.com/swagger-api/swagger-core/pull/3740#issue-532125507
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.1.9 | alwaysResolveAppPath |
true/false | openApi.configuration.alwaysResolveAppPath |
Since version 2.1.9
#3936 a new boolean configuration parameter alwaysResolveAppPath
is available: if set to true
@ApplicationPath
annotation applied to a JAX-RS Application
class will be considered also at build time (e.g. via maven/gradle plugin or programmatic execution) and when exposing via a separate app (e.g. via OpenAPIServlet
).
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.2.12 | openAPI31 |
true/false | openApi.configuration.openAPI31 |
Since version 2.2.12
boolean configuration parameter openAPI31
is available: if set to true
the resolved spec will be processed into a 3.1.0
specification by resolving according to OAS 3.1 rules (e.g. $refs siblings) and using specific 3.1 annotations when available.
(by using convertToOpenapi31=true
)
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.2.12 | convertToOpenapi31 |
true/false |
openApi.configuration.convertToOpenapi31 (DEPRECATED) |
Since version 2.2.12
boolean configuration parameter convertToOpenapi31
is available: if set to true
the resolved spec will be processed to convert it into a 3.1.0
specification by updating the version and converting any incompatible construct into the one supoorted in 3.1. THIS IS DEPRECATED. USE openapi31
instead
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.2.17 | defaultResponseCode |
String | openApi.configuration.defaultResponseCode |
Allows to set the code used when resolving responses with no http status code annotation
Since | Property | Data type | Equivalent init param |
---|---|---|---|
Since 2.2.24 | schemaResolution |
DEFAULT /INLINE /ALL_OF
|
openApi.configuration.schemaResolution |
Since version 2.2.24
configuration parameter schemaResolution
is available.
It allows to specify how object schemas and object properties within schemas are resolved for OAS 3.0 specification:
DEFAULT
: object schemas are bundled into components/schemas and schemas or properties referring to them are resolved as Reference Schema ( with $ref
field populated and no other fields). This is the default when config property is not provided and in versions < 2.2.24. It can causes the issues detailed above.
ALL_OF
: object schemas are bundled into components/schemas and schemas or properties referring to them are resolved as Reference Schema in an item of an allOf
array field, along with any sibling fields resolved into a second allOf
array item.
ALL_OF_REF
: object schemas are bundled into components/schemas and schemas or properties referring to them are resolved as Reference Schema in an item of an allOf
array field, along with any sibling fields resolved into the parent schema.
Applying ALL_OF
and ALL_OF_REF
results in two similar schemas with a slight difference in behavior and tooling support, which is the reason why both options are allowed.
INLINE
: object schemas are resolved into "inline" schemas, therefore not referencing schemas in components/schemas.
NOTE: INLINE
can cause unexpected results or errors and is not recommended
see OpenAPI-3.0-Schema-Resolution for details
{
"resourcePackages": [
"io.swagger.sample.resource"
],
"prettyPrint" : true,
"openAPI": {
"info": {
"version": "1.0",
"title": "Swagger Pet Sample App",
"description": "This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"email": "apiteam@swagger.io"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
}
}
}
}
<servlet>
...
<init-param>
<param-name>openApi.configuration.resourceClasses</param-name>
<param-value>io.swagger.sample.resource.PetResource,io.swagger.sample.resource.UserResource</param-value>
</init-param>
<init-param>
<param-name>openApi.configuration.prettyPrint</param-name>
<param-value>true</param-value>
</init-param>
...
</servlet>
public class Bootstrap extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder()
.servletConfig(config)
.openApiConfiguration(oasConfig)
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new ServletException(e.getMessage(), e);
}
// or
/*
try {
new XmlWebOpenApiContext().servletConfig(config).openApiConfiguration(oasConfig).init();
} catch (OpenApiConfigurationException e) {
e.printStackTrace();
}
*/
}
}
Please also check out swagger samples.
- Jersey JAX-RS container servlet
- Jersey JAX-RS container filter
- RESTEasy JAX-RS container servlet
- JAX-RS Application
- Dropwizard
- Guice
- A bunch of Jersey examples
with configuration file in known location
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
see related sample.
with configuration file in known location
<filter>
<filter-name>jersey</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<!-- param below necessary in Servlet 2.x envs, see https://jersey.github.io/documentation/latest/deployment.html#d0e3419 -->
<init-param>
<param-name>jersey.config.servlet.filter.contextPath</param-name>
<param-value>/api</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>io.swagger.sample.MyApplication</param-value>
</init-param>
<!-- specify resource classes to scan -->
<init-param>
<param-name>openApi.configuration.resourceClasses</param-name>
<param-value>io.swagger.sample.resource.UserResource</param-value>
</init-param>
<init-param>
<param-name>openApi.configuration.prettyPrint</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/sample/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/sample</param-value>
</context-param>
see related sample.
@ApplicationPath("/sample")
public class MyApplication extends Application {
public MyApplication(@Context ServletConfig servletConfig) {
super();
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App bootstrap code")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder()
.servletConfig(servletConfig)
.application(this)
.openApiConfiguration(oasConfig)
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
see related sample.
public class SwaggerSampleApplication extends Application <SwaggerSampleConfiguration> {
public static void main(String[] args) throws Exception {
new SwaggerSampleApplication().run(args);
}
@Override
public void initialize(Bootstrap<SwaggerSampleConfiguration> bootstrap) { }
@Override
public String getName() {
return "swagger-sample";
}
@Override
public void run(SwaggerSampleConfiguration configuration, Environment environment) {
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
environment.jersey().register(new PetResource());
environment.getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
// eg.
environment.jersey().register(new OpenApiResource().openApiConfiguration(oasConfig));
// or
/*
try {
new GenericOpenApiContext().openApiConfiguration(oasConfig).init();
} catch (OpenApiConfigurationException e) {
e.printStackTrace();
}
environment.jersey().register(new OpenApiResource());
*/
// or
//environment.jersey().register(new OpenApiResource().configLocation("/integration/openapi-configuration.json"));
// or provide an openapi.json or yaml / openapi-configuration.json or yaml in classpath
// or
//environment.jersey().register(new OpenApiResource().resourcePackage("io.swagger.sample.resource"));
// or
//environment.jersey().register(new OpenApiResource().resourceClasses("io.swagger.sample.resource.PetResource"));
}
}
see related sample.
public class SwaggerExampleGuiceContextListener extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bind(ServletContainer.class).in(Singleton.class);
bind(ApiOriginFilter.class).in(Singleton.class);
Map<String, String> props = new HashMap<String, String>();
props.put("javax.ws.rs.Application", MyApplication.class.getName());
props.put("jersey.config.server.wadl.disableWadl", "true");
serve("/api/*").with(ServletContainer.class, props);
OpenAPI oas = new OpenAPI();
Info info = new Info()
.title("Swagger Sample App bootstrap code")
.description("This is a sample server Petstore server. You can find out more about Swagger " +
"at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, " +
"you can use the api key `special-key` to test the authorization filters.")
.termsOfService("http://swagger.io/terms/")
.contact(new Contact()
.email("apiteam@swagger.io"))
.license(new License()
.name("Apache 2.0")
.url("http://www.apache.org/licenses/LICENSE-2.0.html"));
oas.info(info);
SwaggerConfiguration oasConfig = new SwaggerConfiguration()
.openAPI(oas)
.prettyPrint(true)
.resourcePackages(Stream.of("io.swagger.sample.resource").collect(Collectors.toSet()));
try {
new JaxrsOpenApiContextBuilder()
.openApiConfiguration(oasConfig)
.buildContext(true);
} catch (OpenApiConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
});
}
}
see related sample.
You can also provide the file location and name as an init param.
If you're defining it as a servlet:
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<init-param>
<param-name>openApi.configuration.location</param-name>
<param-value>/foo/bar/your-openapi-configuration.json</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
And if as a filter:
<filter>
<filter-name>jersey</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<init-param>
<param-name>openApi.configuration.location</param-name>
<param-value>/foo/bar/your-openapi-configuration.json</param-value>
</init-param>
<!-- param below necessary in Servlet 2.x envs, see https://jersey.github.io/documentation/latest/deployment.html#d0e3419 -->
<init-param>
<param-name>jersey.config.servlet.filter.contextPath</param-name>
<param-value>/api</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
In both cases, you can use <init-param/>
to set which packages or classes Jersey should scan/load when it starts. This is where you'd define your own packages and/or classes.
To hook Swagger into your application, you need to add the some of Swagger's packages and classes.
If you're defining it as a servlet:
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
And if as a filter:
<filter>
<filter-name>jersey</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<!-- param below necessary in Servlet 2.x envs, see https://jersey.github.io/documentation/latest/deployment.html#d0e3419 -->
<init-param>
<param-name>jersey.config.servlet.filter.contextPath</param-name>
<param-value>/api</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
You can also use swagger specific init param in a similar way, e.g to scan a subset of the APIs:
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources,
{your.application.packages}
</param-value>
</init-param>
<init-param>
<param-name>openApi.configuration.resourcePackages</param-name>
<param-value>
{your.application.packages.subset}
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
If you're defining it as a servlet:
<servlet>
<servlet-name>jersey</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources.OpenApiResource,
{your.application.classes}
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
And if as a filter:
<filter>
<filter-name>jersey</filter-name>
<filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
io.swagger.v3.jaxrs2.integration.resources.OpenApiResource,
{your.application.classes}
</param-value>
</init-param>
<!-- param below necessary in Servlet 2.x envs, see https://jersey.github.io/documentation/latest/deployment.html#d0e3419 -->
<init-param>
<param-name>jersey.config.servlet.filter.contextPath</param-name>
<param-value>/api</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>jersey</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
A few things to note:
-
{your.application.packages}
,{your.application.classes}
should be replaced by the package(s) or classes of your application, respectively. - The mapping of either servlet or filter depends on your own needs. The above is just an example.
When using a custom Application
subclass, you would need to add swagger-core's providers to the set up process. For example:
public class SampleApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet();
//resources.add(FirstResource.class);
//resources.add(SecondResource.class);
//...
resources.add(io.swagger.v3.jaxrs2.integration.resources.OpenApiResource.class);
return resources;
}
}
The commented part is where you'd add your own application's resources and providers.
Now that you have everything hooked up, don't forget to add some Annotations to your resources, so that those are added to your API definition.
Note: swagger-jaxrs2 reader engine includes by default also methods of scanned resources which are not annotated with @Operation, as long as a jax-rs @Path is defined at class and/or method level, together with the http method annotation (@GET, @POST, etc).
This behaviour is controlled by configuration property readAllResources
which defaults to true. By setting this flag to
false only Operation
annotated methods are considered.