1. Introduction

The Springfox suite of java libraries are all about automating the generation of machine and human readable specifications for JSON APIs written using the spring family of projects. Springfox works by examining an application, once, at runtime to infer API semantics based on spring configurations, class structure and various compile time java Annotations.

1.1. History

Springfox has evolved from a project originally created by Marty Pitt and was named swagger-springmvc. Much kudos goes to Marty.

1.2. Goals

  1. To extend support for a number of the evolving standards targeted at JSON API specification and documentation such as: swagger, RAML and jsonapi.

  2. To extend support for spring technologies other than spring webmvc

1.3. What it’s not

Endorsed or approved by the Spring Framework Contributors

1.4. Development Environment

  • File >> open >> build.gradle

  • Make sure to check the 'use the default gradle wrapper' option.

  • First time build

./gradlew cleanIdea idea
  • To get more output from any gralde commands/tasks append a -i (info) or -d (debug) e.g.

./gradlew build -i

1.4.1. Pre-Commit Build

  • Code quality (code coverage, checkstyle)

./gradlew check

1.4.2. Building reference documentation

 ./gradlew asciidoc --daemon //Using the gradle daemon here makes sense if this is being executed a lot

1.4.3. CI Enviroment

1.5. Releasing

To release a non-snaphot version of Springfox:

  • Execute the the release commands: The below properties are required to run a release:

  • GITHUB_TOKEN

  • BINTRAY_USERNAME

  • BINTRAY_PASSWORD

Recommend using [autoenv](https://github.com/kennethreitz/autoenv) with a .env file at the root of the repo.

    ./gradlew release publishDocs -PbintrayUsername=$BINTRAY_USERNAME -PbintrayPassword=$BINTRAY_PASSWORD
    -PreleaseType=<MAJOR|MINOR|PATCH> -i

The release steps are as follows: - check that the git workspace is clean - check that the local git branch is master - check that the local git branch is the same as origin - gradle test - gradle check - upload (publish) all artifacts to Bintray - Bumps the project version in version.properties - Git tag the release - Git push

1.5.1. Snapshot

This is normally done by the CI server

./gradlew snapshot -PbintrayUsername=<bintrayUsername> -PbintrayPassword=<bintrayPassword>

1.5.2. Override deploy

To bypass the standard release flow and upload directly to bintray use the following task - manually set the version in version.properties

./gradlew clean build bintrayUpload -PbintrayUsername=$BINTRAY_USERNAME -PbintrayPassword=$BINTRAY_PASSWORD -PreleaseType=<MAJOR|MINOR|PATCH>
 --stacktrace

1.5.3. Updating documentation

To update the docs for an existing release pass the updateMode switch

./gradlew publishDocs -PupdateMode

1.5.4. Contributing

Please see the wiki for some guidelines

1.6. Support

If you find issues or bugs please use the github issue springfox project

2. Getting Started

2.1. Dependencies

The Springfox libraries are hosted on bintray and jcenter. The artifacts can be viewed accessed at the following locations:

Springfox has multiple modules and the dependencies will vary depending on the desired API specification standard. Below outlines how to include the springfox-swagger2 module which produces Swagger 2.0 API documentation.

2.1.1. Gradle

Release
repositories {
  jcenter()
}

dependencies {
    compile "io.springfox:springfox-swagger2:2.0.2"
}
Snapshot
repositories {
   maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }
}

dependencies {
    compile "io.springfox:springfox-swagger2:2.0.3-SNAPSHOT"
}

2.1.2. Maven

Release
<repositories>
    <repository>
      <id>jcenter-snapshots</id>
      <name>jcenter</name>
      <url>https://jcenter.bintray.com/</url>
    </repository>
</repositories>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.0.2</version>
</dependency>
Snapshot
<repositories>
    <repository>
      <id>jcenter-snapshots</id>
      <name>jcenter</name>
      <url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
    </repository>
</repositories>

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.0.3-SNAPSHOT</version>
</dependency>

2.1.3. Springfox-swagger2 with Spring Boot

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 *
 *  Copyright 2015 the original author or authors.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

package springfox.springconfig;

import com.fasterxml.classmate.TypeResolver;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.async.DeferredResult;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseMessageBuilder;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.schema.WildcardType;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.AuthorizationScope;
import springfox.documentation.service.SecurityReference;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.petstore.controller.PetController;

import java.util.List;

import static com.google.common.collect.Lists.*;
import static springfox.documentation.schema.AlternateTypeRules.*;

@SpringBootApplication
@EnableSwagger2(1)
@ComponentScan(basePackageClasses = {
    PetController.class
})(2)
public class Swagger2SpringBoot {

  public static void main(String[] args) {
    ApplicationContext ctx = SpringApplication.run(Swagger2SpringBoot.class, args);
  }


  @Bean
  public Docket petApi() {
    return new Docket(DocumentationType.SWAGGER_2)(3)
        .select()(4)
          .apis(RequestHandlerSelectors.any())(5)
          .paths(PathSelectors.any())(6)
          .build()(7)
        .pathMapping("/")(8)
        .directModelSubstitute(LocalDate.class,
            String.class)(9)
        .genericModelSubstitutes(ResponseEntity.class)
        .alternateTypeRules(
            newRule(typeResolver.resolve(DeferredResult.class,
                    typeResolver.resolve(ResponseEntity.class, WildcardType.class)),
                typeResolver.resolve(WildcardType.class)))(10)
        .useDefaultResponseMessages(false)(11)
        .globalResponseMessage(RequestMethod.GET,(12)
            newArrayList(new ResponseMessageBuilder()
                .code(500)
                .message("500 message")
                .responseModel(new ModelRef("Error"))(13)
                .build()))
        .securitySchemes(newArrayList(apiKey()))(14)
        .securityContexts(newArrayList(securityContext()))(15)
        ;
  }

  @Autowired
  private TypeResolver typeResolver;

  private ApiKey apiKey() {
    return new ApiKey("mykey", "api_key", "header");(16)
  }

  private SecurityContext securityContext() {
    return SecurityContext.builder()
        .securityReferences(defaultAuth())
        .forPaths(PathSelectors.regex("/anyPath.*"))(17)
        .build();
  }

  List<SecurityReference> defaultAuth() {
    AuthorizationScope authorizationScope
        = new AuthorizationScope("global", "accessEverything");
    AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
    authorizationScopes[0] = authorizationScope;
    return newArrayList(
        new SecurityReference("mykey", authorizationScopes));(18)
  }

  @Bean
  SecurityConfiguration security() {
    return new SecurityConfiguration((19)
        "test-app-client-id",
        "test-app-realm",
        "test-app",
        "apiKey");
  }

  @Bean
  UiConfiguration uiConfig() {
    return new UiConfiguration((20)
        "validatorUrl");
  }
}
1 Enables Springfox swagger 2
2 Instructs spring where to scan for API controllers
3 Docket, Sringfox’s, primary api configuration mechanism is initialized for swagger specification 2.0
4 select() returns an instance of ApiSelectorBuilder to give fine grained control over the endpoints exposed via swagger.
5 apis() allows selection of RequestHandler’s using a predicate. The example here uses an `any predicate (default). Out of the box predicates provided are any, none, withClassAnnotation, withMethodAnnotation and basPackage.
6 paths() allows selection of Path’s using a predicate. The example here uses an `any predicate (default)
7 The selector requires to be built after configuring the api and path selectors. Out of the box we provide predicates for regex, ant, any, none
8 Adds a servlet path mapping, when the servlet has a path mapping. this prefixes paths with the provided path mapping
9 Convenience rule builder substitutes LocalDate with String when rendering model properties
10 Convenience rule builder that substitutes a generic type with one type parameter with the type parameter. In this example ResponseEntity<T> with T. alternateTypeRules allows custom rules that are a bit more involved. The example substitutes DeferredResult<ResponseEntity<T>> with T generically
11 Flag to indicate if default http response codes need to be used or not
12 Allows globally overriding response messages for different http methods. In this example we override the 500 error code for all `GET`s …​
13 …​and indicate that it will use the response model Error (which will be defined elsewhere)
14 Sets up the security schemes used to protect the apis. Supported schemes are ApiKey, BasicAuth and OAuth
15 Provides a way to globally set up security contexts for operation. The idea here is that we provide a way to select operations to be protected by one of the specified security schemes.
16 Here we use ApiKey as the security schema that is identified by the name mykey
17 Selector for the paths this security context applies to.
18 Here we same key defined in the security scheme mykey
19 Optional swagger-ui security configuration for oauth and apiKey settings
20 Optional swagger-ui ui configuration currently only supports the validation url

There are plenty of more options to configure the Docket. This should provide a good start.

Swagger UI

The springfox-swagger-ui web jar ships with Swagger UI. To include it in a standard Spring Boot application you can add the dependency as follows:

dependencies {
    compile 'io.springfox:springfox-swagger-ui:2.0.2'
}

Pulling in the dependency creates a webjar containing the swagger-ui static content. It adds a JSON endpoint /swagger-resources which lists all of the swagger resources and versions configured for a given application. The Swagger UI page should then be available at http://localhost:8080/swagger-ui.html

Swagger UI

The swagger ui version is specified in ./build.gradle where swaggerUiVersion is a git tag on the [swagger-ui repo] (https://github.com/wordnik/swagger-ui).

All content is served from a webjar convention, relative url taking the following form: webjars/${project.name}/${project.version} e.g: /webjars/springfox-swagger-ui/2.0.2-SNAPSHOT/swagger-ui.html

By default Spring Boot has sensible defaults for serving content from webjars. To configure vanilla spring web mvc apps to serve webjar content see the webjar documentation

2.2. Springfox samples

The springfox-demos repository contains a number of samples.

3. Architecture

A little bit of background; when we started work on 2.0 swagger specification we realized that we’re rewriting the logic to infer the service models and the schema. So we decided to take a step back and break it out into a two step process. First infer the service model into an internal representation. Second create a mapping layer that can map the internal models to different specification formats. Out of the box we will support swagger 1.2 and swagger 2.0, but this leads us to the possibility of supporting other formats and other scenarios as well; for e.g. RAML, ALPS and hypermedia formats.

Accordingly the different modules are split up as shown below.

                                                                                                                               
               +------------------+
               |                  |  Contains the internal service and
               |  springfox-core  |  schema description models along with
               |                  |  their builders.
               +---------+--------+
                         ^
               +---------+--------+
               |                  |  Contains the service provider interfaces that
               |  springfox-spi   |  can be used to extend and enrich the service
               |                  |  models. For e.g. swagger specific annotation
               +---+------+----+--+  processors.
                          |
                          |
 Schema inference         |   spring web specific extensions that can build
 extensions that help     |   the service models based on RequestMapping
 build up the schema for  |   information. This is the heart library that
 the parameters, models   |   infers the service model.
 and responses     |------|----|
   +---------------+----+ | +--+------------------+
   |                    | | |                     |
   |  springfox-schema  | | |springfox-spring-web |
   |                    | | |                     |
   +--------------------+ | +---------------------+
                          |
              +-----------------------+--+
              |                          |   Common swagger specific extensions
              | springfox-swagger-common |   that are aware of the different
              |                          |   swagger annotations.
              +-----+---------------+----+
                    ^               ^
      +-------------+----+     +----+--------------+
      |                  |     |                   |  Configurations, and mapping layer
      |springfox-swagger1|     |springfox-swagger2 |  that know how to convert the
      |                  |     |                   |  service models to swagger 1.2 and
      +------------------+     +-------------------+  swagger 2.0 specification documents.
                                                      Also contains the controller for each
                                                      of the specific formats.

4. Swagger

Springfox supports both version 1.2 and version 2.0 of the Swagger specification. Where possible, the Swagger 2.0 specification is preferable.

The swagger-core annotations, as provided by swagger-core, are typically used to decorate the java source code of an API which is bing 'swaggered'. Springfox is aware of the Swagger-Core Annotations and will favor those annotations over inferred defaults.

4.1. Swagger 1.2 vs Swagger 2.0

One major difference between the two swagger specification is the composition of the generated swagger documentation.

With Swagger 1.2 an applications API is represented as a Resource Listing and multiple API Declarations which has the implication of producing multiple JSON files

With Swagger 2.0 things are much simpler and an application’s API can be represented in a single JSON file.

4.2. Moving from swagger-springmvc?

Here is a guide to help with the transition from 1.0.2 to 2.0.

Legacy documentation is available here.

4.3. Springfox configuration and demo applications

The springfox-demos repository contains a number of sample Spring application which can be used a reference.

5. Configuring Springfox

To enable support for swagger specification 1.2 use the @EnableSwagger annotation

To enable support for swagger specification 2.0 use the @EnableSwagger2 annotation

To document the service we use a Docket. This is changed to be more inline with the fact that expressing the contents of the documentation is agnostic of the format the documentation is rendered.

Docket stands for A summary or other brief statement of the contents of a document; an abstract.

Docket helps configure a subset of the services to be documented and groups them by name. Significant changes to this is the ability to provide an expressive predicate based for api selection.

  import static springfox.documentation.builders.PathSelectors.*;
  import static com.google.common.base.Predicates.*;

  @Bean
  public Docket swaggerSpringMvcPlugin() {
    return new Docket(DocumentationType.SWAGGER_2)
            .groupName("business-api")
            .select()
               //Ignores controllers annotated with @CustomIgnore
              .apis(not(withClassAnnotation(CustomIgnore.class)) //Selection by RequestHandler
              .paths(paths()) // and by paths
              .build()
            .apiInfo(apiInfo())
            .securitySchemes(securitySchemes())
            .securityContext(securityContext());
  }

  //Here is an example where we select any api that matches one of these paths
  private Predicate<String> paths() {
    return or(
        regex("/business.*"),
        regex("/some.*"),
        regex("/contacts.*"),
        regex("/pet.*"),
        regex("/springsRestController.*"),
        regex("/test.*"));
  }

For a list of handy predicates Look at RequestHandlerSelectors and PathSelectors.

5.1. Configuring the ObjectMapper

A simple way to configure the object mapper is to listen for the ObjectMapperConfigured event. Regardless of whether there is a customized ObjectMapper in play with a corresponding MappingJackson2HttpMessageConverter, the library always has a configured ObjectMapper that is customized to serialize swagger 1.2 and swagger 2.0 types.

In order to do this implement the ApplicationListener<ObjectMapperConfigured> interface. The event has a handle to the ObjectMapper that was configured. Configuring application specific ObjectMapper customizations in this applicaiton event handler guarantees that application specific customizations will be applied to each and every ObjectMapper that is in play.

If you encounter a NullPointerException during application startup like this issue. Its because most likely the WebMvcConfigurerAdapter isn’t working. These adapter especially in a non-spring-boot scenarios will only get loaded if the @EnableWebMvc annotation is present.

Caveat to using the library is that it depends on Jackson for serialization, more importantly the ObjectMapper. A good example of where this breaks down is the following issue when using Gson serialization

5.2. Customizing the swagger endpoints.

By default the swagger service descriptions are generated at the following urls

Swagger version Documentation Url Group

2.0

/v2/api-docs?group=external

external group via docket.groupName()

1.2

/api-docs

implicit default group

2.0

/api-docs?group=external

external group via docket.groupName()

2.0

/v2/api-docs

implicit default group

To customize these endpoints, loading a property source with the following properties allows the properties to be overridden

Swagger version Override property

2.0

springfox.documentation.swagger.v2.path

1.2

springfox.documentation.swagger.v1.path

5.3. Overriding property datatypes

Using the ApiModelProperty#dataType we can override the inferred data types. However it is restricted to only allow data types to be specified with a fully qualified class name. For e.g. if we have the following definition

// if com.qualified.ReplaceWith is not a Class that can be created using Class.forName(...)
// Original will be replaced with the new class
@ApiModelProperty(dataType = "com.qualified.ReplacedWith")
public Original getOriginal() { ... }

// if ReplaceWith is not a Class that can be created using Class.forName(...) Original will be preserved
@ApiModelProperty(dataType = "ReplaceWith")
public Original getAnotherOriginal() { ... }

5.4. Docket XML Configuration

To use the plugin you must create a spring java configuration class which uses spring’s @Configuration. This config class must then be defined in your xml application context.

<!-- Required so springfox can access spring's RequestMappingHandlerMapping  -->
<mvc:annotation-driven/>

<bean class="com.yourapp.configuration.MySwaggerConfig"/>
@Configuration
@EnableSwagger //Loads the spring beans required by the framework
public class MySwaggerConfig {

   /**
    * Every Docket bean is picked up by the swagger-mvc framework - allowing for multiple
    * swagger groups i.e. same code base multiple swagger resource listings.
    */
   @Bean
   public Docket customDocket(){
      return new Docket(); //some customization goes here
   }

}

5.5. Docket Spring Java Configuration

  • Use the @EnableSwagger or @EnableSwagger2 annotation.

  • Define one or more Docket instances using springs @Bean annotation.

@Configuration
@EnableWebMvc //NOTE: Only needed in a non-springboot application
@EnableSwagger2
@ComponentScan("com.myapp.controllers")
public class CustomJavaPluginConfig {


   @Bean //Don't forget the @Bean annotation
   public Docket customImplementation(){
      return new Docket()
            .apiInfo(apiInfo())
            .includePatterns(".*pet.*");
   }

   //...
}

5.5.1. Swagger group

A swagger group is a concept introduced by this library which is simply a unique identifier for a Swagger Resource Listing within your application. The reason this concept was introduced was to support applications which require more than one Resource Listing. Why would you need more than one Resource Listing? - A single Spring Web MVC application serves more than one API e.g. publicly facing and internally facing. - A single Spring Web MVC application serves multiple versions of the same API. e.g. v1 and v2

In most cases an application will not need more than one Resource Listing and the concept of swagger groups can be ignored.

5.5.2. Configuring the output of operationId in a Swagger 2.0 spec

As defined operationId was introduced in the Swagger 2.0 spec, the operationId parameter, which was referred to as nickname in pre-2.0 versions of the Swagger spec, provides the author a means by which to describe an API operation with a friendly name . This field is often used by consumers of a Swagger 2.0 spec in order to name functions in generated clients. An example of this can be seen in the swagger-codegen project.

The default value of operationId according to Springfox

By default, when using Springfox in Swagger 2.0 mode, the value of operationID will be rendered using the following structure: “[java_method_name_here]Using[HTTP_verb_here]”. For example, if one has a method getPets() connected to an HTTP GET verb, Springfox will render getPetsUsingGET for the operationId.

Given this annotated method …​
@ApiOperation(value = "")
@RequestMapping(value = "/pets", method = RequestMethod.GET)
public Model getAllThePets() {
    ...
}
the default operationId will render looking like this:
"paths": {
  "/pets": {
    "get": {
            ...
      "operationId":"getAllThePetsUsingGET"
      ...
    }
  }
}
Customizing the value of operationId

In the event you wish to overide the default operationId which Springfox renders, you may do so by providing the nickname element in an @ApiOperation annotation.

Given this annotated method …​
@ApiOperation(value = "", nickname = "getMeAllThePetsPlease")
@RequestMapping(value = "/pets", method = RequestMethod.GET)
public Model getAllThePets() {
    ...
}
…​ the customized operationId will render looking like this:
"paths": {
  "/pets": {
    "get": {
            ...
      "operationId":"getMeAllThePetsPlease"
      ...
    }
  }
}

5.5.3. Changing how Generic Types are Named

By default, types with generics will be labeled with '\u00ab'(<<), '\u00bb'(>>), and commas. This can be problematic with things like swagger-codegen. You can override this behavior by implementing your own GenericTypeNamingStrategy. For example, if you wanted List<String> to be encoded as 'ListOfString' and Map<String, Object> to be encoded as 'MapOfStringAndObject' you could implement the following:

then during plugin customization:

 docket.forCodeGeneration(true|false);

5.6. Extensibility

The library provides a variety of extensibility hooks to enrich/ augment the schema and service models

  • For enriching models and properties (TODO)

  • For enriching services models (TODO)

5.7. Example application

For an examples for spring-boot, vanilla spring applications take a look examples in the demo application.

6. Configuring springfox-staticdocs

Springfox-staticdocs is a module which brings together springfox and swagger2markup. Swagger2Markup is a library which simplifies the generation of an up-to-date RESTful API documentation by combining documentation that’s been hand-written with auto-generated API documentation produced by Springfox. The result is intended to be an up-to-date, easy-to-read, on- and offline user guide. Swagger2Markup converts a Swagger JSON or YAML file into several AsciiDoc or GitHub Flavored Markdown documents which can be converted to HTML, PDF and EPUB. The output of Swagger2Markup can be used as an alternative to swagger-ui and can be served as static content.

6.1. Usage guide

Adding springfox-staticdocs to your project

6.1.1. Maven

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-staticdocs</artifactId>
    <version>2.0.0</version>
    <scope>test</scope>
</dependency>

6.1.2. Gradle

dependencies {
    ...
    compile 'io.springfox:springfox-swagger2:2.0.0'
    testCompile 'io.springfox:springfox-staticdocs:2.0.0'
    ...
}

6.1.3. Generate Markup during an unit test

Spring’s MVC Test framework can be used to make a request to a springfox Swagger endpoint during an unit test. The ResultHandler Swagger2MarkupResultHandler can be used to convert the Swagger JSON response into an AsciiDoc document. The custom ResultHandler is part of springfox-staticdocs. That way you also verify that your Swagger endpoint is working. The following is an example with Spring Boot:

@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
public class Swagger2MarkupTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
    }

    @Test
    public void convertSwaggerToAsciiDoc() throws Exception {
        this.mockMvc.perform(get("/v2/api-docs")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc/generated").build())
                .andExpect(status().isOk());
    }

    @Test
    public void convertSwaggerToMarkdown() throws Exception {
        this.mockMvc.perform(get("/v2/api-docs")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/markdown/generated")
                    .withMarkupLanguage(MarkupLanguage.MARKDOWN).build())
                .andExpect(status().isOk());
    }
}

If you want to combine the generated documentation with your hand-written documentation, then have a look at the user guide of swagger2Markup. You can also include generated CURL request, HTTP request and HTTP response example snippets from spring-restdocs into the generated documentation.

6.1.4. Generated HTML using Swagger2Markup and AsciidoctorJ

asciidoc_html