diff --git a/src/main/java/io/github/robwin/swagger2markup/builder/document/DefinitionsDocument.java b/src/main/java/io/github/robwin/swagger2markup/builder/document/DefinitionsDocument.java index 9b069f68..3be70a55 100644 --- a/src/main/java/io/github/robwin/swagger2markup/builder/document/DefinitionsDocument.java +++ b/src/main/java/io/github/robwin/swagger2markup/builder/document/DefinitionsDocument.java @@ -23,7 +23,8 @@ import io.github.robwin.markup.builder.MarkupDocBuilder; import io.github.robwin.markup.builder.MarkupDocBuilders; import io.github.robwin.swagger2markup.OrderBy; import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig; -import io.github.robwin.swagger2markup.utils.PropertyUtils; +import io.github.robwin.swagger2markup.type.ObjectType; +import io.github.robwin.swagger2markup.type.Type; import io.swagger.models.ComposedModel; import io.swagger.models.Model; import io.swagger.models.RefModel; @@ -192,25 +193,35 @@ public class DefinitionsDocument extends MarkupDocument { propertiesSection(definitions, definitionName, model, docBuilder); } + private class DefinitionPropertyDescriptor extends PropertyDescriptor { + + public DefinitionPropertyDescriptor(Type type) { + super(type); + } + + @Override + public String getDescription(Property property, String propertyName) { + String description; + if(handWrittenDescriptionsEnabled){ + description = handWrittenPathDescription(type.getName().toLowerCase() + "/" + propertyName.toLowerCase(), DESCRIPTION_FILE_NAME); + if(isBlank(description)) { + if (logger.isInfoEnabled()) { + logger.info("Hand-written description file cannot be read. Trying to use description from Swagger source."); + } + description = defaultString(property.getDescription()); + } + } + else{ + description = defaultString(property.getDescription()); + } + return description; + } + } + private void propertiesSection(Map definitions, String definitionName, Model model, MarkupDocBuilder docBuilder){ Map properties = getAllProperties(definitions, model); - List headerAndContent = new ArrayList<>(); - List header = Arrays.asList(NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN); - headerAndContent.add(join(header, DELIMITER)); - if(MapUtils.isNotEmpty(properties)){ - for (Map.Entry propertyEntry : properties.entrySet()) { - Property property = propertyEntry.getValue(); - String propertyName = propertyEntry.getKey(); - List content = Arrays.asList( - propertyName, - propertyDescription(definitionName, propertyName, property), - Boolean.toString(property.getRequired()), - PropertyUtils.getType(property, markupLanguage), - PropertyUtils.getDefaultValue(property)); - headerAndContent.add(join(content, DELIMITER)); - } - docBuilder.tableWithHeaderRow(headerAndContent); - } + Type type = new ObjectType(definitionName, properties); + typeProperties(type, new DefinitionPropertyDescriptor(type), docBuilder); } private Map getAllProperties(Map definitions, Model model) { @@ -268,24 +279,6 @@ public class DefinitionsDocument extends MarkupDocument { } } - private String propertyDescription(String definitionName, String propertyName, Property property) { - String description; - if(handWrittenDescriptionsEnabled){ - description = handWrittenPathDescription(definitionName.toLowerCase() + "/" + propertyName.toLowerCase(), DESCRIPTION_FILE_NAME); - if(isBlank(description)) { - if (logger.isInfoEnabled()) { - logger.info("Hand-written description file cannot be read. Trying to use description from Swagger source."); - } - description = defaultString(property.getDescription()); - } - } - else{ - description = defaultString(property.getDescription()); - } - return description; - } - - /** * Reads a hand-written description * diff --git a/src/main/java/io/github/robwin/swagger2markup/builder/document/MarkupDocument.java b/src/main/java/io/github/robwin/swagger2markup/builder/document/MarkupDocument.java index de56bb19..767d40ba 100644 --- a/src/main/java/io/github/robwin/swagger2markup/builder/document/MarkupDocument.java +++ b/src/main/java/io/github/robwin/swagger2markup/builder/document/MarkupDocument.java @@ -22,13 +22,23 @@ import io.github.robwin.markup.builder.MarkupDocBuilder; import io.github.robwin.markup.builder.MarkupDocBuilders; import io.github.robwin.markup.builder.MarkupLanguage; import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig; +import io.github.robwin.swagger2markup.type.ObjectType; +import io.github.robwin.swagger2markup.type.Type; +import io.github.robwin.swagger2markup.utils.MarkupDocBuilderUtils; +import io.github.robwin.swagger2markup.utils.PropertyUtils; import io.swagger.models.Swagger; +import io.swagger.models.properties.Property; +import org.apache.commons.collections.MapUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.nio.charset.Charset; -import java.util.ResourceBundle; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.apache.commons.lang3.StringUtils.join; /** * @author Robert Winkler @@ -50,7 +60,9 @@ public abstract class MarkupDocument { protected MarkupLanguage markupLanguage; protected MarkupDocBuilder markupDocBuilder; - MarkupDocument(Swagger2MarkupConfig swagger2MarkupConfig){ + protected static AtomicInteger idCount = new AtomicInteger(0); + + MarkupDocument(Swagger2MarkupConfig swagger2MarkupConfig) { this.swagger = swagger2MarkupConfig.getSwagger(); this.markupLanguage = swagger2MarkupConfig.getMarkupLanguage(); this.markupDocBuilder = MarkupDocBuilders.documentBuilder(markupLanguage); @@ -68,18 +80,22 @@ public abstract class MarkupDocument { TAGS = labels.getString("tags"); } + public Integer getNextId() { + return idCount.getAndIncrement(); + } + /** * Builds the MarkupDocument. * * @return the built MarkupDocument * @throws IOException if the files to include are not readable */ - public abstract MarkupDocument build() throws IOException ; + public abstract MarkupDocument build() throws IOException; /** * Returns a string representation of the document. */ - public String toString(){ + public String toString() { return markupDocBuilder.toString(); } @@ -87,11 +103,86 @@ public abstract class MarkupDocument { * Writes the content of the builder to a file and clears the builder. * * @param directory the directory where the generated file should be stored - * @param fileName the name of the file - * @param charset the the charset to use for encoding + * @param fileName the name of the file + * @param charset the the charset to use for encoding * @throws IOException if the file cannot be written */ - public void writeToFile(String directory, String fileName, Charset charset) throws IOException{ + public void writeToFile(String directory, String fileName, Charset charset) throws IOException { markupDocBuilder.writeToFile(directory, fileName, charset); } + + public String uniqueTypeName(String name) { + return name + "-" + getNextId(); + } + + public String typeSchema(Type type) { + if (type == null) + return "Unknown"; + else + return type.displaySchema(markupLanguage); + } + + public void typeProperties(Type type, PropertyDescriptor propertyDescriptor, MarkupDocBuilder docBuilder) { + if (type instanceof ObjectType) { + ObjectType objectType = (ObjectType) type; + List headerAndContent = new ArrayList<>(); + List header = Arrays.asList(NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN); + headerAndContent.add(join(header, DELIMITER)); + if (MapUtils.isNotEmpty(objectType.getProperties())) { + for (Map.Entry propertyEntry : objectType.getProperties().entrySet()) { + Property property = propertyEntry.getValue(); + String propertyName = propertyEntry.getKey(); + Type propertyType = PropertyUtils.getType(property); + List content = Arrays.asList( + propertyName, + propertyDescriptor.getDescription(property, propertyName), + Boolean.toString(property.getRequired()), + typeSchema(propertyType), + PropertyUtils.getDefaultValue(property)); + headerAndContent.add(join(content, DELIMITER)); + } + docBuilder.tableWithHeaderRow(headerAndContent); + } + } + } + + public class PropertyDescriptor { + protected Type type; + + public PropertyDescriptor(Type type) { + this.type = type; + } + + public String getDescription(Property property, String propertyName) { + return defaultString(property.getDescription()); + } + } + + public void sectionTitleLevel(int level, String title, String anchor, MarkupDocBuilder docBuilder) { + if (anchor != null) + docBuilder.textLine(MarkupDocBuilderUtils.anchor(anchor, this.markupLanguage)); + + switch (level) { + case 1: + docBuilder.sectionTitleLevel1(title); + break; + case 2: + docBuilder.sectionTitleLevel2(title); + break; + case 3: + docBuilder.sectionTitleLevel3(title); + break; + case 4: + docBuilder.sectionTitleLevel4(title); + break; + case 5: + if (anchor == null) + docBuilder.textLine(MarkupDocBuilderUtils.anchor(title, this.markupLanguage)); + docBuilder.boldTextLine(title); + break; + default: + throw new RuntimeException("Illegal section level : " + level); + } + + } } diff --git a/src/main/java/io/github/robwin/swagger2markup/builder/document/PathsDocument.java b/src/main/java/io/github/robwin/swagger2markup/builder/document/PathsDocument.java index ae5c6c80..2c831fb2 100644 --- a/src/main/java/io/github/robwin/swagger2markup/builder/document/PathsDocument.java +++ b/src/main/java/io/github/robwin/swagger2markup/builder/document/PathsDocument.java @@ -22,6 +22,9 @@ import com.google.common.base.Optional; import com.google.common.collect.Multimap; import io.github.robwin.swagger2markup.GroupBy; import io.github.robwin.swagger2markup.config.Swagger2MarkupConfig; +import io.github.robwin.swagger2markup.type.ObjectType; +import io.github.robwin.swagger2markup.type.RefType; +import io.github.robwin.swagger2markup.type.Type; import io.github.robwin.swagger2markup.utils.ParameterUtils; import io.github.robwin.swagger2markup.utils.PropertyUtils; import io.swagger.models.*; @@ -62,6 +65,8 @@ public class PathsDocument extends MarkupDocument { private static final String DESCRIPTION_FOLDER_NAME = "paths"; private static final String DESCRIPTION_FILE_NAME = "description"; private final String PARAMETER; + private final String DEFINITIONS; + private boolean examplesEnabled; private String examplesFolderPath; @@ -84,6 +89,7 @@ public class PathsDocument extends MarkupDocument { TYPE_COLUMN = labels.getString("type_column"); HTTP_CODE_COLUMN = labels.getString("http_code_column"); PARAMETER = labels.getString("parameter"); + DEFINITIONS = labels.getString("definitions"); this.pathsGroupedBy = swagger2MarkupConfig.getPathsGroupedBy(); if(isNotBlank(swagger2MarkupConfig.getExamplesFolderPath())){ @@ -176,14 +182,17 @@ public class PathsDocument extends MarkupDocument { */ private void path(String methodAndPath, Operation operation) { if(operation != null){ + List localDefinitions = new ArrayList<>(); + pathTitle(methodAndPath, operation); descriptionSection(operation); - parametersSection(operation); - responsesSection(operation); + localDefinitions.addAll(parametersSection(operation)); + localDefinitions.addAll(responsesSection(operation)); consumesSection(operation); producesSection(operation); tagsSection(operation); examplesSection(operation); + localDefinitionsSection(localDefinitions); } } @@ -222,6 +231,19 @@ public class PathsDocument extends MarkupDocument { } } + /** + * Adds a path section title to the document. + * + * @param title the path title + */ + private void addPathSectionTitle(String title) { + if(pathsGroupedBy.equals(GroupBy.AS_IS)){ + this.markupDocBuilder.sectionTitleLevel3(title); + }else{ + this.markupDocBuilder.sectionTitleLevel4(title); + } + } + /** * Adds a path description to the document. * @@ -254,41 +276,45 @@ public class PathsDocument extends MarkupDocument { private void pathDescription(String description) { if (isNotBlank(description)) { - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(DESCRIPTION); - }else{ - this.markupDocBuilder.sectionTitleLevel4(DESCRIPTION); - } + addPathSectionTitle(DESCRIPTION); this.markupDocBuilder.paragraph(description); } } - private void parametersSection(Operation operation) { + private List parametersSection(Operation operation) { List parameters = operation.getParameters(); + List localDefinitions = new ArrayList<>(); if(CollectionUtils.isNotEmpty(parameters)){ List headerAndContent = new ArrayList<>(); // Table header row List header = Arrays.asList(TYPE_COLUMN, NAME_COLUMN, DESCRIPTION_COLUMN, REQUIRED_COLUMN, SCHEMA_COLUMN, DEFAULT_COLUMN); headerAndContent.add(join(header, DELIMITER)); for(Parameter parameter : parameters){ - String type = ParameterUtils.getType(parameter, markupLanguage); + Type type = ParameterUtils.getType(parameter); + if (type instanceof ObjectType) { + String localTypeName = parameter.getName(); + type.setName(localTypeName); + type.setUniqueName(uniqueTypeName(localTypeName)); + localDefinitions.add(type); + + type = new RefType(type); + } String parameterType = WordUtils.capitalize(parameter.getIn() + PARAMETER); // Table content row List content = Arrays.asList( parameterType, parameter.getName(), parameterDescription(operation, parameter), - Boolean.toString(parameter.getRequired()), type, + Boolean.toString(parameter.getRequired()), + typeSchema(type), ParameterUtils.getDefaultValue(parameter)); headerAndContent.add(join(content, DELIMITER)); } - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(PARAMETERS); - }else{ - this.markupDocBuilder.sectionTitleLevel4(PARAMETERS); - } + addPathSectionTitle(PARAMETERS); this.markupDocBuilder.tableWithHeaderRow(headerAndContent); } + + return localDefinitions; } /** @@ -330,11 +356,7 @@ public class PathsDocument extends MarkupDocument { private void consumesSection(Operation operation) { List consumes = operation.getConsumes(); if(CollectionUtils.isNotEmpty(consumes)){ - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(CONSUMES); - }else{ - this.markupDocBuilder.sectionTitleLevel4(CONSUMES); - } + addPathSectionTitle(CONSUMES); this.markupDocBuilder.unorderedList(consumes); } @@ -343,11 +365,7 @@ public class PathsDocument extends MarkupDocument { private void producesSection(Operation operation) { List produces = operation.getProduces(); if(CollectionUtils.isNotEmpty(produces)){ - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(PRODUCES); - }else{ - this.markupDocBuilder.sectionTitleLevel4(PRODUCES); - } + addPathSectionTitle(PRODUCES); this.markupDocBuilder.unorderedList(produces); } } @@ -356,7 +374,7 @@ public class PathsDocument extends MarkupDocument { if(pathsGroupedBy.equals(GroupBy.AS_IS)) { List tags = operation.getTags(); if (CollectionUtils.isNotEmpty(tags)) { - this.markupDocBuilder.sectionTitleLevel3(TAGS); + addPathSectionTitle(TAGS); this.markupDocBuilder.unorderedList(tags); } } @@ -376,30 +394,18 @@ public class PathsDocument extends MarkupDocument { String exampleFolder = summary.replace(".", "").replace(" ", "_").toLowerCase(); Optional curlExample = example(exampleFolder, CURL_EXAMPLE_FILE_NAME); if(curlExample.isPresent()){ - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_CURL); - }else{ - this.markupDocBuilder.sectionTitleLevel4(EXAMPLE_CURL); - } + addPathSectionTitle(EXAMPLE_CURL); this.markupDocBuilder.paragraph(curlExample.get()); } Optional requestExample = example(exampleFolder, REQUEST_EXAMPLE_FILE_NAME); if(requestExample.isPresent()){ - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_REQUEST); - }else{ - this.markupDocBuilder.sectionTitleLevel4(EXAMPLE_REQUEST); - } + addPathSectionTitle(EXAMPLE_REQUEST); this.markupDocBuilder.paragraph(requestExample.get()); } Optional responseExample = example(exampleFolder, RESPONSE_EXAMPLE_FILE_NAME); if(responseExample.isPresent()){ - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(EXAMPLE_RESPONSE); - }else{ - this.markupDocBuilder.sectionTitleLevel4(EXAMPLE_RESPONSE); - } + addPathSectionTitle(EXAMPLE_RESPONSE); this.markupDocBuilder.paragraph(responseExample.get()); } }else{ @@ -425,7 +431,7 @@ public class PathsDocument extends MarkupDocument { logger.info("Example file processed: {}", path); } try { - return Optional.fromNullable(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim()); + return Optional.of(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim()); } catch (IOException e) { if (logger.isWarnEnabled()) { logger.warn(String.format("Failed to read example file: %s", path), e); @@ -458,7 +464,7 @@ public class PathsDocument extends MarkupDocument { logger.info("Description file processed: {}", path); } try { - return Optional.fromNullable(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim()); + return Optional.of(FileUtils.readFileToString(path.toFile(), StandardCharsets.UTF_8).trim()); } catch (IOException e) { if (logger.isWarnEnabled()) { logger.warn(String.format("Failed to read description file: %s", path), e); @@ -476,8 +482,9 @@ public class PathsDocument extends MarkupDocument { return Optional.absent(); } - private void responsesSection(Operation operation) { + private List responsesSection(Operation operation) { Map responses = operation.getResponses(); + List localDefinitions = new ArrayList<>(); if(MapUtils.isNotEmpty(responses)){ List csvContent = new ArrayList<>(); csvContent.add(HTTP_CODE_COLUMN + DELIMITER + DESCRIPTION_COLUMN + DELIMITER + SCHEMA_COLUMN); @@ -485,19 +492,39 @@ public class PathsDocument extends MarkupDocument { Response response = entry.getValue(); if(response.getSchema() != null){ Property property = response.getSchema(); - String type = PropertyUtils.getType(property, markupLanguage); - csvContent.add(entry.getKey() + DELIMITER + response.getDescription() + DELIMITER + type); + Type type = PropertyUtils.getType(property); + if (type instanceof ObjectType) { + String localTypeName = "Response " + entry.getKey(); + type.setName(localTypeName); + type.setUniqueName(uniqueTypeName(localTypeName)); + localDefinitions.add(type); + + type = new RefType(type); + } + csvContent.add(entry.getKey() + DELIMITER + response.getDescription() + DELIMITER + typeSchema(type)); }else{ csvContent.add(entry.getKey() + DELIMITER + response.getDescription() + DELIMITER + "No Content"); } } - if(pathsGroupedBy.equals(GroupBy.AS_IS)){ - this.markupDocBuilder.sectionTitleLevel3(RESPONSES); - }else{ - this.markupDocBuilder.sectionTitleLevel4(RESPONSES); - } + addPathSectionTitle(RESPONSES); this.markupDocBuilder.tableWithHeaderRow(csvContent); } + return localDefinitions; } + private void localDefinitionsSection(List definitions) { + if(CollectionUtils.isNotEmpty(definitions)){ + addPathSectionTitle(DEFINITIONS); + + for (Type definition: definitions) { + if(pathsGroupedBy.equals(GroupBy.AS_IS)){ + sectionTitleLevel(4, definition.getName(), definition.getUniqueName(), this.markupDocBuilder); + }else{ + sectionTitleLevel(5, definition.getName(), definition.getUniqueName(), this.markupDocBuilder); + } + typeProperties(definition, new PropertyDescriptor(definition), this.markupDocBuilder); + } + } + + } } diff --git a/src/main/java/io/github/robwin/swagger2markup/type/ArrayType.java b/src/main/java/io/github/robwin/swagger2markup/type/ArrayType.java new file mode 100644 index 00000000..797ca5a2 --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/type/ArrayType.java @@ -0,0 +1,27 @@ +package io.github.robwin.swagger2markup.type; + +import io.github.robwin.markup.builder.MarkupLanguage; + +public class ArrayType extends Type { + + protected String collectionFormat; + protected Type ofType; + + public ArrayType(String name, Type ofType) { + this(name, ofType, null); + } + + public ArrayType(String name, Type ofType, String collectionFormat) { + super(name == null ? "array" : name); + this.collectionFormat = collectionFormat; + this.ofType = ofType; + } + + @Override + public String displaySchema(MarkupLanguage language) { + String collectionFormat = ""; + if (this.collectionFormat != null) + collectionFormat = this.collectionFormat + " "; + return collectionFormat + ofType.displaySchema(language) + " array"; + } +} diff --git a/src/main/java/io/github/robwin/swagger2markup/type/BasicType.java b/src/main/java/io/github/robwin/swagger2markup/type/BasicType.java new file mode 100644 index 00000000..3af7459c --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/type/BasicType.java @@ -0,0 +1,27 @@ +package io.github.robwin.swagger2markup.type; + +import io.github.robwin.markup.builder.MarkupLanguage; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +public class BasicType extends Type { + + protected String format; + + public BasicType(String name) { + this(name, null); + } + + public BasicType(String name, String format) { + super(name); + this.format = format; + } + + @Override + public String displaySchema(MarkupLanguage language) { + if (isNotBlank(this.format)) + return this.name + "(" + this.format + ")"; + else + return this.name; + } +} diff --git a/src/main/java/io/github/robwin/swagger2markup/type/EnumType.java b/src/main/java/io/github/robwin/swagger2markup/type/EnumType.java new file mode 100644 index 00000000..9ed9ff29 --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/type/EnumType.java @@ -0,0 +1,22 @@ +package io.github.robwin.swagger2markup.type; + +import io.github.robwin.markup.builder.MarkupLanguage; + +import java.util.List; + +import static org.apache.commons.lang3.StringUtils.join; + +public class EnumType extends Type { + + protected List values; + + public EnumType(String name, List values) { + super(name == null ? "enum" : name); + this.values = values; + } + + @Override + public String displaySchema(MarkupLanguage language) { + return "enum" + " (" + join(values, ", ") + ")"; + } +} diff --git a/src/main/java/io/github/robwin/swagger2markup/type/ObjectType.java b/src/main/java/io/github/robwin/swagger2markup/type/ObjectType.java new file mode 100644 index 00000000..36731c33 --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/type/ObjectType.java @@ -0,0 +1,29 @@ +package io.github.robwin.swagger2markup.type; + +import io.github.robwin.markup.builder.MarkupLanguage; +import io.swagger.models.properties.Property; + +import java.util.Map; + +public class ObjectType extends Type { + + protected Map properties; + + public ObjectType(String name, Map properties) { + super(name == null ? "object" : name); + this.properties = properties; + } + + @Override + public String displaySchema(MarkupLanguage language) { + return "object"; + } + + public Map getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } +} diff --git a/src/main/java/io/github/robwin/swagger2markup/type/RefType.java b/src/main/java/io/github/robwin/swagger2markup/type/RefType.java new file mode 100644 index 00000000..f6a41441 --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/type/RefType.java @@ -0,0 +1,20 @@ +package io.github.robwin.swagger2markup.type; + +import io.github.robwin.markup.builder.MarkupLanguage; +import io.github.robwin.swagger2markup.utils.MarkupDocBuilderUtils; + +public class RefType extends Type { + + public RefType(String name) { + super(name); + } + + public RefType(Type type) { + super(type.name, type.uniqueName); + } + + @Override + public String displaySchema(MarkupLanguage language) { + return MarkupDocBuilderUtils.crossReference(getName(), getUniqueName(), language); + } +} diff --git a/src/main/java/io/github/robwin/swagger2markup/type/Type.java b/src/main/java/io/github/robwin/swagger2markup/type/Type.java new file mode 100644 index 00000000..2660cccd --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/type/Type.java @@ -0,0 +1,39 @@ +package io.github.robwin.swagger2markup.type; + +import io.github.robwin.markup.builder.MarkupLanguage; +import org.apache.commons.lang3.Validate; + +public abstract class Type { + + protected String name; + protected String uniqueName; + + public Type(String name, String uniqueName) { + Validate.notBlank(name); + + this.name = name; + this.uniqueName = uniqueName; + } + + public Type(String name) { + this(name, name); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public String getUniqueName() { + return uniqueName; + } + + public void setUniqueName(String uniqueName) { + this.uniqueName = uniqueName; + } + + public abstract String displaySchema(MarkupLanguage language); +} diff --git a/src/main/java/io/github/robwin/swagger2markup/utils/MarkupDocBuilderUtils.java b/src/main/java/io/github/robwin/swagger2markup/utils/MarkupDocBuilderUtils.java new file mode 100644 index 00000000..f3038d76 --- /dev/null +++ b/src/main/java/io/github/robwin/swagger2markup/utils/MarkupDocBuilderUtils.java @@ -0,0 +1,41 @@ +package io.github.robwin.swagger2markup.utils; + +import io.github.robwin.markup.builder.MarkupDocBuilder; +import io.github.robwin.markup.builder.MarkupLanguage; + +/* + * FIXME : this code should go to markup-document-builder project + */ +public class MarkupDocBuilderUtils { + + public static String normalizeAnchor(String anchor) { + return anchor.replaceAll("[^0-9a-zA-Z]", "_"); + } + + public static String anchor(String text, MarkupLanguage language) { + switch (language) { + case ASCIIDOC: + return "[[" + normalizeAnchor(text) + "]]"; + default: + return ""; + } + } + + public static String crossReference(String text, String anchor, MarkupLanguage language) { + switch (language) { + case ASCIIDOC: + String normalizedAnchor = normalizeAnchor(anchor); + if (text == null && !anchor.equals(normalizedAnchor)) + text = anchor; + if (text == null) + return "<<" + normalizedAnchor + ">>"; + else + return "<<" + normalizedAnchor + "," + text + ">>"; + default: + if (text == null) + return anchor; + else + return text; + } + } +} diff --git a/src/main/java/io/github/robwin/swagger2markup/utils/ModelUtils.java b/src/main/java/io/github/robwin/swagger2markup/utils/ModelUtils.java index fd16a310..9e2d5fac 100644 --- a/src/main/java/io/github/robwin/swagger2markup/utils/ModelUtils.java +++ b/src/main/java/io/github/robwin/swagger2markup/utils/ModelUtils.java @@ -18,35 +18,34 @@ */ package io.github.robwin.swagger2markup.utils; +import io.github.robwin.swagger2markup.type.ArrayType; +import io.github.robwin.swagger2markup.type.ObjectType; +import io.github.robwin.swagger2markup.type.RefType; +import io.github.robwin.swagger2markup.type.Type; import io.swagger.models.ArrayModel; import io.swagger.models.Model; import io.swagger.models.ModelImpl; import io.swagger.models.RefModel; -import io.github.robwin.markup.builder.MarkupLanguage; import org.apache.commons.lang3.Validate; public final class ModelUtils { /** - * Retrieves the type of a model, or otherwise "NOT FOUND" + * Retrieves the type of a model, or otherwise null * * @param model the model - * @param markupLanguage the markup language which is used to generate the files - * @return the type of the model, or otherwise "NOT FOUND" + * @return the type of the model, or otherwise null */ - public static String getType(Model model, MarkupLanguage markupLanguage) { + public static Type getType(Model model) { Validate.notNull(model, "model must not be null!"); if (model instanceof ModelImpl) { - return ((ModelImpl) model).getType(); + return new ObjectType(null, model.getProperties()); } else if (model instanceof RefModel) { - switch (markupLanguage){ - case ASCIIDOC: return "<<" + ((RefModel) model).getSimpleRef() + ">>"; - default: return ((RefModel) model).getSimpleRef(); - } + return new RefType(((RefModel) model).getSimpleRef()); } else if (model instanceof ArrayModel) { ArrayModel arrayModel = ((ArrayModel) model); - return PropertyUtils.getType(arrayModel.getItems(), markupLanguage) + " " + arrayModel.getType(); + return new ArrayType(null, PropertyUtils.getType(arrayModel.getItems())); } - return "NOT FOUND"; + return null; } } diff --git a/src/main/java/io/github/robwin/swagger2markup/utils/ParameterUtils.java b/src/main/java/io/github/robwin/swagger2markup/utils/ParameterUtils.java index e8c0789d..112c0a77 100644 --- a/src/main/java/io/github/robwin/swagger2markup/utils/ParameterUtils.java +++ b/src/main/java/io/github/robwin/swagger2markup/utils/ParameterUtils.java @@ -18,7 +18,7 @@ */ package io.github.robwin.swagger2markup.utils; -import io.github.robwin.markup.builder.MarkupLanguage; +import io.github.robwin.swagger2markup.type.*; import io.swagger.models.Model; import io.swagger.models.parameters.AbstractSerializableParameter; import io.swagger.models.parameters.BodyParameter; @@ -29,28 +29,27 @@ import org.apache.commons.lang3.Validate; import java.util.List; -import static org.apache.commons.lang3.StringUtils.*; +import static org.apache.commons.lang3.StringUtils.defaultString; public final class ParameterUtils { /** - * Retrieves the type of a parameter, or otherwise an empty String + * Retrieves the type of a parameter, or otherwise null * * @param parameter the parameter - * @param markupLanguage the markup language which is used to generate the files - * @return the type of the parameter, or otherwise an empty String + * @return the type of the parameter, or otherwise null */ - public static String getType(Parameter parameter, MarkupLanguage markupLanguage){ - Validate.notNull(parameter, "property must not be null!"); - String type = "NOT FOUND"; + public static Type getType(Parameter parameter){ + Validate.notNull(parameter, "parameter must not be null!"); + Type type = null; if(parameter instanceof BodyParameter){ BodyParameter bodyParameter = (BodyParameter)parameter; Model model = bodyParameter.getSchema(); if(model != null){ - type = ModelUtils.getType(model, markupLanguage); + type = ModelUtils.getType(model); }else{ - type = "string"; + type = new BasicType("string"); } } @@ -58,38 +57,18 @@ public final class ParameterUtils { AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter; List enums = serializableParameter.getEnum(); if(CollectionUtils.isNotEmpty(enums)){ - type = "enum" + " (" + join(enums, ", ") + ")"; + type = new EnumType(null, enums); }else{ - type = getTypeWithFormat(serializableParameter.getType(), serializableParameter.getFormat()); + type = new BasicType(serializableParameter.getType(), serializableParameter.getFormat()); } - if(type.equals("array")){ + if(type.getName().equals("array")){ String collectionFormat = serializableParameter.getCollectionFormat(); - type = collectionFormat + " " + PropertyUtils.getType(serializableParameter.getItems(), markupLanguage) + " " + type; + type = new ArrayType(null, PropertyUtils.getType(serializableParameter.getItems()), collectionFormat); } } else if(parameter instanceof RefParameter){ RefParameter refParameter = (RefParameter)parameter; - switch (markupLanguage){ - case ASCIIDOC: return "<<" + refParameter.getSimpleRef() + ">>"; - default: return refParameter.getSimpleRef(); - } - } - return defaultString(type); - } - - /** - * Adds the format to the type, if a format is available - * - * @param typeWithoutFormat the type - * @param format the format - * @return returns the type and format, if a format is available - */ - private static String getTypeWithFormat(String typeWithoutFormat, String format) { - String type; - if(isNotBlank(format)){ - type = defaultString(typeWithoutFormat) + " (" + format + ")"; - }else{ - type = defaultString(typeWithoutFormat); + type = new RefType(refParameter.getSimpleRef()); } return type; } @@ -101,7 +80,7 @@ public final class ParameterUtils { * @return the default value of the parameter, or otherwise an empty String */ public static String getDefaultValue(Parameter parameter){ - Validate.notNull(parameter, "property must not be null!"); + Validate.notNull(parameter, "parameter must not be null!"); String defaultValue = ""; if(parameter instanceof AbstractSerializableParameter){ AbstractSerializableParameter serializableParameter = (AbstractSerializableParameter)parameter; diff --git a/src/main/java/io/github/robwin/swagger2markup/utils/PropertyUtils.java b/src/main/java/io/github/robwin/swagger2markup/utils/PropertyUtils.java index e9b234b7..288c7ca6 100644 --- a/src/main/java/io/github/robwin/swagger2markup/utils/PropertyUtils.java +++ b/src/main/java/io/github/robwin/swagger2markup/utils/PropertyUtils.java @@ -19,6 +19,7 @@ package io.github.robwin.swagger2markup.utils; import io.github.robwin.markup.builder.MarkupLanguage; +import io.github.robwin.swagger2markup.type.*; import io.swagger.models.properties.*; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.Validate; @@ -34,39 +35,37 @@ public final class PropertyUtils { * Retrieves the type and format of a property. * * @param property the property - * @param markupLanguage the markup language which is used to generate the files * @return the type of the property */ - public static String getType(Property property, MarkupLanguage markupLanguage){ + public static Type getType(Property property){ Validate.notNull(property, "property must not be null!"); - String type; + Type type = null; if(property instanceof RefProperty){ RefProperty refProperty = (RefProperty)property; - switch (markupLanguage){ - case ASCIIDOC: return "<<" + refProperty.getSimpleRef() + ">>"; - default: return refProperty.getSimpleRef(); - } + type = new RefType(refProperty.getSimpleRef()); }else if(property instanceof ArrayProperty){ ArrayProperty arrayProperty = (ArrayProperty)property; Property items = arrayProperty.getItems(); - type = getType(items, markupLanguage) + " " + arrayProperty.getType(); + type = new ArrayType(null, getType(items)); }else if(property instanceof StringProperty){ StringProperty stringProperty = (StringProperty)property; List enums = stringProperty.getEnum(); if(CollectionUtils.isNotEmpty(enums)){ - type = "enum" + " (" + join(enums, ", ") + ")"; + type = new EnumType(null, enums); }else{ - type = property.getType(); + type = new BasicType(property.getType()); } + }else if(property instanceof ObjectProperty) { + type = new ObjectType(null, ((ObjectProperty) property).getProperties()); } else{ if(isNotBlank(property.getFormat())){ - type = defaultString(property.getType()) + " (" + property.getFormat() + ")"; + type = new BasicType(property.getType(), property.getFormat()); }else{ - type = property.getType(); + type = new BasicType(property.getType()); } } - return defaultString(type); + return type; } /**