View on GitHub

Lazydoc

A framework for automatic REST-API documentation

Download this project as a .zip file Download this project as a tar.gz file

Lazydoc is a modular framework to collect documentation data from your source code and generate artifacts for documentation frameworks like Swagger, DocBook, etc.

Getting Started

To use lazydoc you can integrate the lazydoc maven plugin in your maven pom file or you can create a custom java class which configures and executes lazydoc. The different configuration options are described in the configuration section below.

Lazydoc is currently just supporting a parser for Spring REST, but it will also support JAX-RS and other REST frameworks in the future.

Use the lazydoc maven plugin

Lazydoc provides a maven plugin which configures and executes lazydoc.

Lazydoc maven plugin example

        <plugin>
            <groupId>org.lazydoc</groupId>
            <artifactId>lazydoc-plugin</artifactId>
            <version>1.0.0</version>
            <executions>
                <execution>
                    <goals>
                        <goal>document</goal>
                    </goals>
                    <phase>compile</phase>
                </execution>
            </executions>
            <configuration>
                <config>
                    <packageToSearchForControllers>org.lazydoc.example</packageToSearchForControllers>
                    <documentationSuffix>Documentation</documentationSuffix>
                </config>
                <printerConfigs>
                    <printerConfig>
                        <className>org.lazydoc.printer.DocBookDocumentationPrinter</className>
                        <outputPath>${project.parent.basedir}/lazydoc-docbookexample/src/docbkx/lazydoc/</outputPath>
                        <params>
                           <docbook.filename>lazydoc.xml</docbook.filename>
                        </params>
                    </printerConfig>
                </printerConfigs>
            </configuration>
        </plugin>

Use a custom java class

To use lazydoc you can create a small java class which configures and executes lazydoc.

Lazydoc configuration class example

  public class ExampleDocParser {

      public static void main(String[] args) throws Exception {
          Config config = new Config();
          config.setPackageToSearchForControllers("org.lazydoc.example");
          new LazyDoc(config).document();
      }
  }

To get started you just need to set the package where lazydoc should search for controllers. Now just start it with the maven java exec plugin. As main class use the class you created. As argument the project basedir is provided which is used to point the generators to the path they should create the artifacts.

  <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <version>1.1.1</version>
      <executions>
         <execution>
            <phase>compile</phase>
            <goals>
               <goal>java</goal>
            </goals>
            <configuration>
                <includeProjectDependencies>true</includeProjectDependencies>
                <mainClass>org.lazydoc.example.simple.doc.ExampleDocParser</mainClass>
                <arguments>
                    <argument>${project.basedir}/</argument>
                </arguments>
            </configuration>
         </execution>
      </executions>
  </plugin>

Documenting a controller

Lazydoc is using an annotation based approache to add the additional information which is needed to generate the documentation artifacts. The following example shows the usage of the annotations. See detailed description of the annotations below.

@Controller
@DomainDescription(order = 1, name = "Customer", description="Operations for customer management")
public class RestfulCustomerController {
    ....
    @RequestMapping(value = "/customers/{customerId}", method = RequestMethod.GET)
    @OperationDescription(description = "Returns the customer for the given id")
    @ParameterDescription({@Parameter(name="customerId", description = "The id of the customer to be returned")})
    @ResponseDescription(description = "The customer requested by id")
    public @ResponseBody Customer getCustomer(@PathVariable long customerId) {
        ....
    }

    @RequestMapping(value = "/customers", method = RequestMethod.POST)
    @OperationDescription(description = "Creates a new customer")
    @ParameterDescription({@Parameter(name="requestBody", description = "The data of the customer to be created")})
    @ResponseDescription(description = "The newly created customer")
    public @ResponseBody Customer createCustomer(@RequestBody Customer customer) {
        ....
    }

    @RequestMapping(value = "/customers/{customerId}", method = RequestMethod.PUT)
    @OperationDescription(description = "Updates a customer specified by the id")
    @ParameterDescription({
            @Parameter(name = "customerId", description = "The id of the customer to be updated"),
            @Parameter(name="requestBody", description = "The data of the customer to be created")})
    @ResponseDescription(description = "The updated customer")
    public @ResponseBody Customer updateCustomer(@PathVariable long customerId, @RequestBody Customer customer) {
        ....
    }

    @ExceptionHandler(CustomerNotFoundException.class)
    @ResponseStatus(value = HttpStatus.NOT_FOUND)
    @ErrorDescription(description = "This error occurs if the customer was not found")
    public @ResponseBody
    String handleException(Exception ex) {
        return "The customer was not found";
    }

}

In this example the annotations for documentation are put directly in the controller class. But this litters the class too much. Lazydoc offers the possibility to put the documentation annotations in a different class. Currently there is just a strategy to configure a suffix for the controller class to lookup the documentation class. So for example if your controller is RestfulCustomerController and your suffix is Documentation, lazydoc will look for a (abstract) class or interface with the name RestfulCustomerControllerDocumentation in the same package. The package with the documentation class can be in a different project as long as it is accessible in the compile phase.

The annotation can be included in your project with the following maven dependency

  <dependency>
       <groupId>org.lazydoc</groupId>
       <artifactId>lazydoc-annotation</artifactId>
       <version>1.0.0</version>
  </dependency>

Configuration

The configuration of lazydoc is done with a common configuration and a configuration for every printer for what you want to generate documentation for.

Config

packageToSearchForControllers

The package where lazydoc can find the controllers which should be documented.

breakOnUndocumented

If this flag is set to true the build process will fail if there are undocumented artifacts.

documentationSuffix

Lazydoc offers to put the documentation annotation in a different class in the same package. This can be used to avoid loitering the controller class with documentation annotation. If the documentationSuffix is defined lazydoc will look for the documentation annotations in a class or interface with controller name + documentation suffix. So for example if the controller is named RestfulCustomerController and the documentation suffix is Documentation lazydoc expects to find a class RestfulCustomerControllerDocumentation

dataTypeSuffix

If the controller uses for its data transfer object (DTO) a common suffix like DTO or VO (Value Object) or something else you can tell lazydoc with the dataTypeSuffix to not include the suffix in the documentation. So for example if the DTO class is called CustomerDTO lazydoc will just use the Customer part in the documentation.

baseDTOClassname

If the DTO classes all share a common base DTO class lazydoc can check if all classes found are inherited by this base class. The name of the class is configured with baseDTOClassname. This is useful if DTO classes and entity classes are mixed in the controller and just DTO classes should be used for documentation. The lazydoc annotations support type parameters which specifies the used type instead of using reflection. So for example if a spring resolver resolves a client id to a Client entity you can specify with the type that the client should be a Long or String or so. If the type is not set lazydoc will check that the client type is not inherited from the configured baseDTOClassname and will report an error. If this parameter is not configured (default) everything is parsed.

customAnnotationToBeIgnored

If there are already custom annotations used in the controllers which can be used to define methods or controllers to be ignored the class name of this annotation can be configured with this parameter.

+++++ The following parameters will be updated in the near future +++++

exceptionHandlerInvoker

abstractControllerClassForCommonExceptionHandlers

instanceControllerClassForCommonExceptionHandlers

controllerClassToStopErrorInspection

PrinterConfig

className

The classname of the printer which should be used.

outputPath

The output path where the printer should generate the documentation artifacts.

params

The params for the printer are provided as a map if needed.

Annotations

DomainDescription

name

The name of the domain.

shortDescription

The short description can be used in printers to describe in a short way what the domain is about. If the short description is not set the description will be used.

description

The description of the domain provides a more detailed content what the domain is about.

order

The order of the domain can be used to define the order of the different domains. If you have more than one domain you have to provide the order of the domains. So for example 1 Customer 2 Products etc.

subDomain

If the domain is too big so that it is useful to divide it in subcategories you can define subdomains.

externalDocumentation

If there are some additional informations to your domain which are not part of the documentation of your operations you can specify an external documentation which can be interpreted by the documentation printer and can be included in the generated documentation artifacts.

SubDomainDescription

name

The name of the sub domain.

shortDescription

The short description can be used in printers to describe in a short way what the sub domain is about. If the short description is not set the description will be used.

description

The description of the domain provides a more detailed content what the sub domain is about.

order

The order of the sub domain can be used to define the order of the different sub domains. If you have more than one sub domain you have to provide the order of the sub domains. So for example domain Customer subdomains 1 master data management 2 registrations 3 contact address etc.

externalDocumentation

If there are some additional informations to your sub domain which are not part of the documentation of your operations you can specify an external documentation which can be interpreted by the documentation printer and can be included in the generated documentation artifacts.

OperationDescription

order

The order of the operations in your controller class. If not set the operations are sorted alphabetically

description

The description what the operation is doing

shortDescription

The short description what the operation is doing. If the short description is not set the description will be used.

nickname

The nickname is the name of the method in the controller class. The nickname is for example used by swagger for expanding the details of an operation. If two operations have the same name because they are overloaded swagger can would expand both operation details. So with this parameter you can specify an alternative nick name

notes

A more detailed description of the operation.

externalDocumentation

If there are some additional informations to your operation you can specify an external documentation which can be interpreted by the documentation printer and can be included in the generated documentation artifacts. For example tables which explain some things in a more detailed way. Things which can not be put easily in a common description.

ExternalDocumentation

location

The location where the external location can be found. Should be a relative location and can be interpreted by the printers differently

postion

The position where the external documentation should be inserted. It can be inserted before or after the domain / subdomain / operation descriptions. The position is an enum of type InsertPosition which can have the values TOP or BOTTOM.

ParameterDescription

value

The List of parameter annotations.

Parameter

name

The name of the parameter to be described. If the parameter is a path variable lazydoc expects the name of path variable in the URI. If the parameter is for an request body lazydoc expects the name of the parameter to be requestBody. If the parameter is a query parameter the name of the parameter has to be defined in the RequestParam annotation. These conventions are necessary because until Java 8 it is not possible to get the name of a variable in a method signature through reflection. Lazydoc is currently implemented for Java 7.

type

The type of the parameter. Normally this is discovered through reflection and you don't need to specify a type. But sometimes it is useful to specify a class instead of relying on reflection. For example when an ID is already resolved to a complex type, but it should be just String or Long etc.

description

The description of the parameter.

ignore

Flag if the parameter should be ignored for documentation.

PropertyDescription

description

The description of the property of the data type.

addPossibleEnumValues

If the data type property is an enum this flag determines if the enum values will automatically added to the description of the property. The default for this value is true, so by default all enum values are listed in the description.

type

The type of the property. Normally this is discovered through reflection and you don't need to specify a type. But sometimes it is useful to specify a class instead of relying on reflection. For example when an ID is already resolved to a complex type, but it should be just String or Long etc.

required

Flag if the property is required or optional. Default is false.

onlyRequest

Flag if the property only appears in the request. Default is false. If both values for onlyRequest and onlyResponse are false (for example if you didn't set this flags in the annotation) the property will be considered for the request.

onlyResponse

Flag if the property only appears in the response. Default is false. If both values for onlyRequest and onlyResponse are false (for example if you didn't set this flags in the annotation) the property will be considered for the response.

Sample

value

A sample can be specified to give the printer the opportunity to build a JSON example with the sample values of the data type properties. The value is a array of string, so it can contain just a simple string or if you need samples for a list you can specify more values as a string array.

++++++ Will be updated soon ++++++++