Swagger JAX-RS Generator

A Maven plug-in that can generate Swagger documentation for JAX-RS web services. Produces documentation for REST web services at build-time rather than run-time so that application runtime dependencies are kept to a minimum.

License

License

Categories

Categories

Swagger Program Interface REST Frameworks
GroupId

GroupId

com.greensopinion.swagger
ArtifactId

ArtifactId

jaxrs-gen
Last Version

Last Version

1.3.5
Release Date

Release Date

Type

Type

maven-plugin
Description

Description

Swagger JAX-RS Generator
A Maven plug-in that can generate Swagger documentation for JAX-RS web services. Produces documentation for REST web services at build-time rather than run-time so that application runtime dependencies are kept to a minimum.
Project URL

Project URL

https://github.com/greensopinion/swagger-jaxrs-maven
Project Organization

Project Organization

David Green
Source Code Management

Source Code Management

https://github.com/greensopinion/swagger-jaxrs-maven.git

Download jaxrs-gen

How to add to project

<plugin>
    <groupId>com.greensopinion.swagger</groupId>
    <artifactId>jaxrs-gen</artifactId>
    <version>1.3.5</version>
</plugin>

Dependencies

compile (8)

Group / Artifact Type Version
org.apache.maven : maven-plugin-api jar 3.0
org.apache.maven : maven-core jar 3.0
com.google.guava : guava jar 16.0.1
org.reflections : reflections jar 0.9.9-RC1
org.javassist : javassist jar 3.19.0-GA
io.swagger : swagger-annotations jar 1.5.3
javax.ws.rs : jsr311-api jar 1.1.1
com.google.code.gson : gson jar 2.2.4

provided (1)

Group / Artifact Type Version
org.apache.maven.plugin-tools : maven-plugin-annotations jar 3.4

test (4)

Group / Artifact Type Version
com.sun.jersey.contribs : jersey-multipart jar 1.19
junit : junit jar 4.8
org.mockito : mockito-core jar 2.8.47
org.assertj : assertj-core jar 3.7.0

Project Modules

There are no modules declared in this project.

Overview

This project provides a Maven plug-in that can generate Swagger documentation for JAX-RS web services. The goal is to produce documentation for REST web services at build-time rather than run-time so that applicaiton runtime dependencies are kept to a minimum.

What it does

  1. Generates Swagger documentation as .json files at build-time
  2. Handles a specific style of JAX-RS service authoring; for example it expects annotations to be fairly complete

Motivation

This project was created because documentation for web services is important and Swagger is a great way to do it. To date Swagger documentation is either written completely by hand or is generated using Swagger annotations at runtime. Authoring Swagger docs from scratch means that the documentation is separate from the source code and it’s easy for the documentation to become inaccurate. Runtime generation of Swagger documentation adds a huge number of dependencies to your project’s runtime (about 30 the last time I counted). Dependencies add complexity and maintenance overhead, and also add overhead to maintaining an IP-clean project.

The goal of this project is to enable annotation-based documentation of JAX-RS web services without adding numerous project runtime dependencies.

Project Requirements

In order to generate Swagger documentation for your project the following requirements must be met:

  • Your project has at least one JAX-RS for REST-based services
  • Your JAX-RS service is annotated with Swagger API annotations
  • Your project has a Maven build

This has been tested with Jersey JAX-RS services, but does not depend on Jersey directly so should work with JAX-RS services targeting other frameworks as well.

Maven Project Setup

Your project’s Maven pom should look something like this:

Add a Swagger annotations dependency so that Swagger annotations can be used in your project:


    <dependency>
      <groupId>io.swagger</groupId>
      <artifactId>swagger-annotations</artifactId>
      <version>1.5.3</version>
    </dependency>

Add this plug-in to your pom.xml’s build:

<build>
		<finalName>web</finalName>
		<plugins>
			<plugin>
				<groupId>com.greensopinion.swagger</groupId>
				<artifactId>jaxrs-gen</artifactId>
				<version>1.3.5</version>
				<configuration>
					<apiVersion>1.0</apiVersion>
					<apiBasePath>/api/latest</apiBasePath>
					<packageNames>
						<param>my.project.package.name</param> <!-- the package name of your project's JAX-RS web services. -->
					</packageNames>
					<outputFolder>${project.build.directory}/web/api/docs</outputFolder>
				</configuration>
				<executions>
					<execution>
						<goals>
							<goal>generate</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>

Building Documentation

Documentation is created as part of the compile step as follows:

mvn compile

Your Maven output should look something like this:

[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building web Maven Webapp 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ web ---
[INFO] Copying 0 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.5.1:compile (default-compile) @ web ---
[INFO] Compiling 13 source files to /myproject/web/target/classes
[INFO] 
[INFO] --- jaxrs-gen:1.0-SNAPSHOT:generate (default) @ web ---
[INFO] API class: myproject.web.MyService
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.796s
[INFO] Finished at: Fri Mar 14 07:35:36 PDT 2014
[INFO] Final Memory: 19M/310M
[INFO] ------------------------------------------------------------------------

Generated file layout

Generated documentation is created in files in a nested folder structure that mimics the layout of your services. For example, if you have two REST services as follows:

@Path("/pet")
public class PetService { ... }
@Path("/owner")
public class OwnerService { ... }

The generated documentation would be created as follows:

<outputFolder>
  +- index.json     <-- the Swagger resource listing
  +- pet
  |  +- index.json  <-- the pet Swagger API declaration 
  +- owner
     +- index.json  <-- the owner Swagger API declaration

This layout combined with the Web Application configuration below will enable Swagger UI to interact with the services.

Web Application

I recommend having your web application serve up the Swagger documentation; that way your documentation is always up to date and available for those using its REST services.

The following addition to your web.xml will cause the generated documentation to be served as expected:

<welcome-file-list>
    <!-- other welcome files go here --> 
    <welcome-file>index.json</welcome-file>
</welcome-file-list>

Example JAX-RS Service

This Maven plug-in expects your JAX-RS service to look something like this:


@Path("/pets")
@Api(value = "/pets", description = "Operations about pets")
@Produces(MediaType.APPLICATION_JSON)
public class PetService {

	@GET
	@ApiOperation(value = "List all pets", notes = "List all pets. Results are paginated.", response = PetListing.class)
	public PetListing list(@QueryParam("start") @DefaultValue("0") int start,
			@QueryParam("count") @DefaultValue("50") int count) {
		return null;
	}

	@GET
	@Path("/{id}")
	@ApiOperation(value = "Retrieve pet by id", notes = "Retrieves a pet by it's id.", response = Pet.class)
	@ApiResponses(value = { @ApiResponse(code = 404, message = "Pet not found", response = ServerError.class) })
	public Pet retrievePet(@PathParam("id") long id) {
		return null;
	}

	@DELETE
	@Path("/{id}")
	@ApiOperation(value = "Delete pet by id", notes = "Deletes a pet by it's id.")
	@ApiResponses(value = { @ApiResponse(code = 404, message = "Pet not found", response = ServerError.class) })
	public void deletePet(@PathParam("id") long id) {
	}

	@PUT
	@ApiOperation(value = "Creates a new pet", notes = "Creates a new pet with the given name.", response = PetHandle.class)
	public PetHandle createPet(PetValues petValues) {
		return null;
	}

	@POST
	@Path("/{id}")
	@Produces(MediaType.APPLICATION_JSON)
	@ApiOperation(value = "Updates a pet", notes = "Updates an existing pet with the provided details.")
	@ApiResponses(value = { @ApiResponse(code = 404, message = "Pet not found", response = ServerError.class) })
	public void updatePet(Pet pet, @PathParam("id") long id) {
	}
}

The following Swagger description was generated from the above API:

api-docs.json


{
  "apiVersion": "1.0",
  "swaggerVersion": "1.2",
  "apis": [
    {
      "path": "/pets"
    }
  ]
}

pet.json


{
  "apiVersion": "1.0.1",
  "swaggerVersion": "1.2",
  "basePath": "/api/latest",
  "resourcePath": "/pets/{petId}",
  "description": "Operations about pets",
  "apis": [
    {
      "path": "/pet",
      "description": "Operations about pets",
      "operations": [
        {
          "method": "GET",
          "summary": "List all pets",
          "notes": "List all pets. Results are paginated.",
          "type": "PetListing",
          "nickname": "list",
          "produces": [
            "application/json"
          ],
          "parameters": [
            {
              "name": "start",
              "defaultValue": "0",
              "required": false,
              "allowMultiple": false,
              "type": "integer",
              "format": "int32",
              "paramType": "query"
            },
            {
              "name": "count",
              "defaultValue": "50",
              "required": false,
              "allowMultiple": false,
              "type": "integer",
              "format": "int32",
              "paramType": "query"
            }
          ]
        },
        {
          "method": "PUT",
          "summary": "Creates a new pet",
          "notes": "Creates a new pet with the given name.",
          "type": "PetHandle",
          "nickname": "createPet",
          "produces": [
            "application/json"
          ],
          "parameters": [
            {
              "name": "body",
              "required": true,
              "allowMultiple": false,
              "type": "PetValues",
              "paramType": "body"
            }
          ]
        }
      ]
    },
    {
      "path": "/pet/{id}",
      "description": "Operations about pets",
      "operations": [
        {
          "method": "DELETE",
          "summary": "Delete pet by id",
          "notes": "Deletes a pet by it's id.",
          "type": "void",
          "nickname": "deletePet",
          "produces": [
            "application/json"
          ],
          "parameters": [
            {
              "name": "id",
              "required": true,
              "allowMultiple": false,
              "type": "integer",
              "format": "int64",
              "paramType": "path"
            }
          ],
          "responseMessages": [
            {
              "code": 404,
              "message": "Pet not found",
              "responseModel": "ServerError"
            }
          ]
        },
        {
          "method": "GET",
          "summary": "Retrieve pet by id",
          "notes": "Retrieves a pet by it's id.",
          "type": "Pet",
          "nickname": "retrievePet",
          "produces": [
            "application/json"
          ],
          "parameters": [
            {
              "name": "id",
              "required": true,
              "allowMultiple": false,
              "type": "integer",
              "format": "int64",
              "paramType": "path"
            }
          ],
          "responseMessages": [
            {
              "code": 404,
              "message": "Pet not found",
              "responseModel": "ServerError"
            }
          ]
        },
        {
          "method": "POST",
          "summary": "Updates a pet",
          "notes": "Updates an existing pet with the provided details.",
          "type": "void",
          "nickname": "updatePet",
          "produces": [
            "application/json"
          ],
          "parameters": [
            {
              "name": "body",
              "required": true,
              "allowMultiple": false,
              "type": "Pet",
              "paramType": "body"
            },
            {
              "name": "id",
              "required": true,
              "allowMultiple": false,
              "type": "integer",
              "format": "int64",
              "paramType": "path"
            }
          ],
          "responseMessages": [
            {
              "code": 404,
              "message": "Pet not found",
              "responseModel": "ServerError"
            }
          ]
        }
      ]
    }
  ],
  "models": {
    "Pet": {
      "id": "Pet",
      "required": [
        "id",
        "name",
        "kind"
      ],
      "properties": {
        "id": {
          "type": "integer",
          "format": "int64"
        },
        "name": {
          "type": "string",
          "description": "The name of the pet"
        },
        "kind": {
          "type": "PetKind",
          "description": "The kind of pet",
          "enum": [
            "DOG",
            "CAT",
            "REPTILE",
            "FISH",
            "HORSE",
            "OTHER"
          ]
        },
        "notes": {
          "type": "string"
        }
      }
    },
    "PetHandle": {
      "id": "PetHandle",
      "required": [
        "id"
      ],
      "properties": {
        "id": {
          "type": "integer",
          "format": "int64"
        },
        "name": {
          "type": "string",
          "description": "The name of the pet"
        }
      }
    },
    "PetListing": {
      "id": "PetListing",
      "description": "A listing of pets",
      "required": [],
      "properties": {
        "start": {
          "type": "integer",
          "format": "int32",
          "description": "The 0-based start index offset."
        },
        "count": {
          "type": "integer",
          "format": "int32",
          "description": "The number of pets requested.  May differ from the actual number of pets in the listing."
        },
        "total": {
          "type": "integer",
          "format": "int32",
          "description": "The total number of pets in the system that correspond to the listing."
        },
        "pets": {
          "type": "List",
          "items": {
            "$ref": "PetHandle"
          },
          "description": "The list of pet handles."
        }
      }
    },
    "PetValues": {
      "id": "PetValues",
      "required": [
        "name",
        "kind"
      ],
      "properties": {
        "name": {
          "type": "string",
          "description": "The name of the pet"
        },
        "kind": {
          "type": "PetKind",
          "description": "The kind of pet",
          "enum": [
            "DOG",
            "CAT",
            "REPTILE",
            "FISH",
            "HORSE",
            "OTHER"
          ]
        },
        "notes": {
          "type": "string"
        }
      }
    },
    "ServerError": {
      "id": "ServerError",
      "description": "A representation of an error, providing an error code and message.",
      "required": [
        "code"
      ],
      "properties": {
        "code": {
          "type": "string",
          "description": "The error code, which can be used to identify the type of error."
        },
        "message": {
          "type": "string",
          "description": "The message describing the error."
        },
        "detail": {
          "type": "string",
          "description": "Detail of the error which can be used for diagnostic purposes."
        }
      }
    }
  }
}

Building

Build using Maven as follows:

`mvn clean verify`

Build status on Travis CI:

Building for Release

Build using Maven as follows:

mvn -Possrh -Darguments=-Dgpg.passphrase=... release:prepare
mvn -Possrh -Darguments=-Dgpg.passphrase=... release:perform

License

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.

Versions

Version
1.3.5
1.3.3
1.3.0