Skip to content

Commit

Permalink
Add SwaggerReader and swaggerExtensions + some cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
alexrashed authored and ara-nts committed Aug 7, 2017
1 parent 8103bd5 commit 611f9ad
Show file tree
Hide file tree
Showing 29 changed files with 3,147 additions and 226 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -7,3 +7,4 @@
/.classpath
/.project
/generated/
/test-output/
10 changes: 7 additions & 3 deletions README.md
Expand Up @@ -55,8 +55,8 @@ Import the plugin in your project by adding following configuration in your `plu
| **name** | **description** |
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `springmvc` | Tell the plugin your project is a JAX-RS(`false`) or a SpringMvc(`true`) project |
| `locations` **required**| Classes containing Swagger's annotation ```@Api```, or packages containing those classes can be configured here. Multiple values must be separated by commas. Example: `<locations>com.github.kongchen.swagger.sample.wordnik.resource,com.github.kongchen.swagger.sample.wordnik.resource2</locations>` |
| `schemes` | The transfer protocol of the API. Values MUST be from the list: `"http"`, `"https"`, `"ws"`, `"wss"`. Multiple values must be separated by commas. Example: `<schemes>http,https</schemes>` |
| `locations` **required**| Classes containing Swagger's annotation ```@Api```, or packages containing those classes can be configured here. Multiple values must be separated by commas. Example: `<locations><location>com.github.kongchen.swagger.sample.wordnik.resource</location><location>com.github.kongchen.swagger.sample.wordnik.resource2</location></locations>` |
| `schemes` | The transfer protocol of the API. Values MUST be from the list: `"http"`, `"https"`, `"ws"`, `"wss"`. Multiple values must be separated by commas. Example: `<schemes><scheme>http</scheme><scheme>https</scheme></schemes>` |
| `host` | The host (name or ip) serving the API. This MUST be the host only and does not include the scheme nor sub-paths. It MAY include a port. The host does not support [path templating](https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#pathTemplating).|
| `basePath` | The base path on which the API is served, which is relative to the host. The value MUST start with a leading slash (/). The basePath does not support [path templating](https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#pathTemplating). |
| `descriptionFile` | A Path to file with description to be set to Swagger Spec 2.0's [info Object](https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#infoObject) |
Expand All @@ -67,13 +67,14 @@ Import the plugin in your project by adding following configuration in your `plu
| `outputFormats` | The format types of the generated swagger spec. Valid values are `json`, `yaml` or both `json,yaml`. The `json` format is default.|
| `swaggerDirectory` | The directory of generated `swagger.json` file. If null, no `swagger.json` will be generated. |
| `swaggerFileName` | The filename of generated `filename.json` file. If null, `swagger.json` will be generated. |
| `swaggerApiReader` | If not null, the value should be a full name of the class implementing `com.github.kongchen.swagger.docgen.reader.ClassSwaggerReader`. This allows you to flexibly implement/override the reader's implementation. Default is `com.github.kongchen.swagger.docgen.reader.JaxrsReader` |
| `swaggerApiReader` | If not null, the value should be a full name of the class implementing `com.github.kongchen.swagger.docgen.reader.ClassSwaggerReader`. This allows you to flexibly implement/override the reader's implementation. `com.github.kongchen.swagger.docgen.reader.SwaggerReader` can be used to strictly use the official Swagger reader in order to generate the exact same output as Swagger''s runtime generation (with all its bugs). Default is `com.github.kongchen.swagger.docgen.reader.JaxrsReader`. |
| `attachSwaggerArtifact` | If enabled, the generated `swagger.json` file will be attached as a maven artifact. The `swaggerDirectory`'s name will be used as an artifact classifier. Default is `false`. |
| `modelSubstitute` | The model substitute file's path, see more details [below](#model-substitution)|
| `typesToSkip` | Nodes of class names to explicitly skip during parameter processing. More details [below](#typesToSkip)|
| `apiModelPropertyAccessExclusions` | Allows the exclusion of specified `@ApiModelProperty` fields. This can be used to hide certain model properties from the swagger spec. More details [below](#apiModelPropertyAccessExclusions)|
| `jsonExampleValues` | If `true`, all example values in `@ApiModelProperty` will be handled as json raw values. This is useful for creating valid examples in the generated json for all property types, including non-string ones. |
| `modelConverters` | List of custom implementations of `io.swagger.converter.ModelConverter` that should be used when generating the swagger files. |
| `swaggerExtensions` | List of custom implementations of `io.swagger.jaxrs.ext.SwaggerExtension` that should be used when generating the swagger files. |

# <a id="templatefile">Template File</a>

Expand Down Expand Up @@ -315,6 +316,9 @@ There's a [sample here](https://github.com/swagger-maven-plugin/swagger-maven-ex
<swaggerApiReader>com.wordnik.swagger.jaxrs.reader.DefaultJaxrsApiReader</swaggerApiReader>
<attachSwaggerArtifact>true</attachSwaggerArtifact>
<modelConverters>io.swagger.validator.BeanValidator</modelConverters>
<swaggerExtensions>
<swaggerExtension>com.example.VendorExtension</swaggerExtension>
</swaggerExtensions>
</apiSource>
</apiSources>
</configuration>
Expand Down
Expand Up @@ -14,13 +14,23 @@
import com.github.jknack.handlebars.helper.StringHelpers;
import com.github.jknack.handlebars.io.TemplateLoader;
import com.github.kongchen.swagger.docgen.mavenplugin.ApiSource;
import com.github.kongchen.swagger.docgen.mavenplugin.SecurityDefinition;
import com.github.kongchen.swagger.docgen.reader.AbstractReader;
import com.github.kongchen.swagger.docgen.reader.ClassSwaggerReader;
import com.github.kongchen.swagger.docgen.reader.ModelModifier;
import com.google.common.collect.Sets;

import io.swagger.annotations.Api;
import io.swagger.config.FilterFactory;
import io.swagger.converter.ModelConverter;
import io.swagger.converter.ModelConverters;
import io.swagger.core.filter.SpecFilter;
import io.swagger.core.filter.SwaggerSpecFilter;
import io.swagger.jaxrs.ext.SwaggerExtension;
import io.swagger.jaxrs.ext.SwaggerExtensions;
import io.swagger.models.Scheme;
import io.swagger.models.Swagger;
import io.swagger.models.auth.SecuritySchemeDefinition;
import io.swagger.models.properties.Property;
import io.swagger.util.Json;
import io.swagger.util.Yaml;
Expand All @@ -29,6 +39,7 @@
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.lang.reflect.Constructor;
Expand All @@ -37,7 +48,12 @@
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
* @author chekong 05/13/2013
Expand Down Expand Up @@ -90,10 +106,51 @@ public AbstractDocumentSource(Log log, ApiSource apiSource) throws MojoFailureEx
this.apiSource = apiSource;
}

public void loadDocuments() throws GenerateException {
if (apiSource.getSwaggerInternalFilter() != null) {
try {
LOG.info("Setting filter configuration: " + apiSource.getSwaggerInternalFilter());
FilterFactory.setFilter((SwaggerSpecFilter) Class.forName(apiSource.getSwaggerInternalFilter()).newInstance());
} catch (Exception e) {
throw new GenerateException("Cannot load: " + apiSource.getSwaggerInternalFilter(), e);
}
}

ClassSwaggerReader reader = resolveApiReader();

// the reader may modify the extensions list, therefore add the additional swagger extensions
// after the instantiation of the reader
if (apiSource.getSwaggerExtensions() != null) {
List<SwaggerExtension> extensions = SwaggerExtensions.getExtensions();
extensions.addAll(resolveSwaggerExtensions());
}

swagger = reader.read(getValidClasses());

if (apiSource.getSecurityDefinitions() != null) {
for (SecurityDefinition sd : apiSource.getSecurityDefinitions()) {
for (Map.Entry<String, SecuritySchemeDefinition> entry : sd.getDefinitions().entrySet()) {
swagger.addSecurityDefinition(entry.getKey(), entry.getValue());
}
}
}

public abstract void loadDocuments() throws GenerateException;
// sort security defs to make output consistent
Map<String, SecuritySchemeDefinition> defs = swagger.getSecurityDefinitions();
if (defs != null) {
Map<String, SecuritySchemeDefinition> sortedDefs = new TreeMap<String, SecuritySchemeDefinition>();
sortedDefs.putAll(defs);
swagger.setSecurityDefinitions(sortedDefs);
}

public void toSwaggerDocuments(String uiDocBasePath, String outputFormats, String encoding) throws GenerateException {
if (FilterFactory.getFilter() != null) {
swagger = new SpecFilter().filter(swagger, FilterFactory.getFilter(),
new HashMap<String, List<String>>(), new HashMap<String, String>(),
new HashMap<String, List<String>>());
}
}

public void toSwaggerDocuments(String uiDocBasePath, String outputFormats, String encoding) throws GenerateException {
toSwaggerDocuments(uiDocBasePath, outputFormats, null, encoding);
}

Expand Down Expand Up @@ -245,24 +302,6 @@ public void loadTypesToSkip() throws GenerateException {
}
}

private void writeInDirectory(File dir, Swagger swaggerDoc,
String basePath) throws GenerateException {

// try {
// File serviceFile = createFile(dir, filename);
// String json = JsonSerializer.asJson(swaggerDoc);
// JsonNode tree = mapper.readTree(json);
// if (basePath != null) {
// ((ObjectNode) tree).put("basePath", basePath);
// }
//
// JsonUtil.mapper().writerWithDefaultPrettyPrinter()
// .writeValue(serviceFile, tree);
// } catch (IOException e) {
// throw new GenerateException(e);
// }
}

protected File createFile(File dir, String outputResourcePath) throws IOException {
File serviceFile;
int i = outputResourcePath.lastIndexOf("/");
Expand Down Expand Up @@ -343,17 +382,44 @@ public CharSequence apply(String value, Options options) throws IOException {
handlebars.registerHelper(StringHelpers.lower.name(), StringHelpers.lower);
}

private String getUrlParent(URL url) {
if (url == null) {
return null;
}

String strurl = url.toString();
int idx = strurl.lastIndexOf('/');
if (idx == -1) {
return strurl;
}
return strurl.substring(0, idx);
/**
* Resolves the API reader which should be used to scan the classes.
*
* @return ClassSwaggerReader to use
* @throws GenerateException if the reader cannot be created / resolved
*/
protected abstract ClassSwaggerReader resolveApiReader() throws GenerateException;

/**
* Returns the set of classes which should be included in the scanning.
*
* @return Set<Class<?>> containing all valid classes
*/
protected Set<Class<?>> getValidClasses() {
return apiSource.getValidClasses(Api.class);
}

/**
* Resolves all {@link SwaggerExtension} instances configured to be added to the Swagger configuration.
*
* @return Collection<SwaggerExtension> which should be added to the swagger configuration
* @throws GenerateException if the swagger extensions could not be created / resolved
*/
protected List<SwaggerExtension> resolveSwaggerExtensions() throws GenerateException {
List<String> clazzes = apiSource.getSwaggerExtensions();
List<SwaggerExtension> resolved = new ArrayList<SwaggerExtension>();
if (clazzes != null) {
for (String clazz : clazzes) {
SwaggerExtension extension;
try {
extension = (SwaggerExtension) Class.forName(clazz).newInstance();
} catch (Exception e) {
throw new GenerateException("Cannot load Swagger extension: " + clazz, e);
}
resolved.add(extension);
}
}
return resolved;
}

protected ClassSwaggerReader getCustomApiReader(String customReaderClassName) throws GenerateException {
Expand Down
@@ -1,20 +1,21 @@
package com.github.kongchen.swagger.docgen.mavenplugin;

import io.swagger.annotations.SwaggerDefinition;
import io.swagger.models.Contact;
import io.swagger.models.Info;
import io.swagger.models.License;
import org.apache.maven.plugins.annotations.Parameter;
import org.reflections.Reflections;
import org.springframework.core.annotation.AnnotationUtils;

import java.io.File;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.apache.maven.plugins.annotations.Parameter;
import org.reflections.Reflections;
import org.springframework.core.annotation.AnnotationUtils;

import io.swagger.annotations.SwaggerDefinition;
import io.swagger.models.Contact;
import io.swagger.models.Info;
import io.swagger.models.License;

/**
* User: kongchen
* Date: 3/7/13
Expand Down Expand Up @@ -96,6 +97,13 @@ public class ApiSource {
@Parameter
private String swaggerApiReader;

/**
* List of full qualified class names of SwaggerExtension implementations to be
* considered for the generation
*/
@Parameter
private List<String> swaggerExtensions;

@Parameter
private boolean springmvc;

Expand Down Expand Up @@ -326,8 +334,16 @@ public String getSwaggerApiReader() {
public void setSwaggerApiReader(String swaggerApiReader) {
this.swaggerApiReader = swaggerApiReader;
}

public List<String> getSwaggerExtensions() {
return swaggerExtensions;
}

public void setSwaggerExtensions(List<String> swaggerExtensions) {
this.swaggerExtensions = swaggerExtensions;
}

public String getApiSortComparator() {
public String getApiSortComparator() {
return apiSortComparator;
}

Expand Down
@@ -1,28 +1,18 @@
package com.github.kongchen.swagger.docgen.mavenplugin;

import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;

import com.github.kongchen.swagger.docgen.AbstractDocumentSource;
import com.github.kongchen.swagger.docgen.GenerateException;
import com.github.kongchen.swagger.docgen.reader.ClassSwaggerReader;
import com.github.kongchen.swagger.docgen.reader.JaxrsReader;
import io.swagger.annotations.Api;
import io.swagger.config.FilterFactory;
import io.swagger.core.filter.SpecFilter;
import io.swagger.core.filter.SwaggerSpecFilter;
import io.swagger.models.auth.SecuritySchemeDefinition;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
* @author chekong
* 05/13/2013
*/
public class MavenDocumentSource extends AbstractDocumentSource {
private final SpecFilter specFilter = new SpecFilter();

public MavenDocumentSource(ApiSource apiSource, Log log, String encoding) throws MojoFailureException {
super(log, apiSource);
Expand All @@ -31,43 +21,7 @@ public MavenDocumentSource(ApiSource apiSource, Log log, String encoding) throws
}
}

@Override
public void loadDocuments() throws GenerateException {
if (apiSource.getSwaggerInternalFilter() != null) {
try {
LOG.info("Setting filter configuration: " + apiSource.getSwaggerInternalFilter());
FilterFactory.setFilter((SwaggerSpecFilter) Class.forName(apiSource.getSwaggerInternalFilter()).newInstance());
} catch (Exception e) {
throw new GenerateException("Cannot load: " + apiSource.getSwaggerInternalFilter(), e);
}
}

swagger = resolveApiReader().read(apiSource.getValidClasses(Api.class));

if (apiSource.getSecurityDefinitions() != null) {
for (SecurityDefinition sd : apiSource.getSecurityDefinitions()) {
for (Map.Entry<String, SecuritySchemeDefinition> entry : sd.getDefinitions().entrySet()) {
swagger.addSecurityDefinition(entry.getKey(), entry.getValue());
}
}
}

// sort security defs to make output consistent
Map<String, SecuritySchemeDefinition> defs = swagger.getSecurityDefinitions();
if (defs != null) {
Map<String, SecuritySchemeDefinition> sortedDefs = new TreeMap<String, SecuritySchemeDefinition>();
sortedDefs.putAll(defs);
swagger.setSecurityDefinitions(sortedDefs);
}

if (FilterFactory.getFilter() != null) {
swagger = new SpecFilter().filter(swagger, FilterFactory.getFilter(),
new HashMap<String, List<String>>(), new HashMap<String, String>(),
new HashMap<String, List<String>>());
}
}

private ClassSwaggerReader resolveApiReader() throws GenerateException {
protected ClassSwaggerReader resolveApiReader() throws GenerateException {
String customReaderClassName = apiSource.getSwaggerApiReader();
if (customReaderClassName == null) {
JaxrsReader reader = new JaxrsReader(swagger, LOG);
Expand Down

0 comments on commit 611f9ad

Please sign in to comment.