diff --git a/.gitignore b/.gitignore
index 0eb9f8bff4..b9a4c97ec8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ target/
.classpath
.project
.settings/
+modules/swagger-parser/src/test/resources/relative-file-references/yaml
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/SwaggerMigrator.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/SwaggerMigrator.java
index 3b09c00985..3087fb8e70 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/SwaggerMigrator.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/SwaggerMigrator.java
@@ -9,15 +9,15 @@
/**
* Core interface for JSON migration
- *
+ *
* This takes a {@link JsonNode} as an input and outputs the transformed
* {@link JsonNode}.
- *
+ *
* Note that this interface makes no guarantee as to whether
* a new {@code JsonNode} is returned, or the input argument is
* returned (altered or not). If this distinction is important, please document
* it in your implementation(s).
- *
+ *
* You can either implement this interface directly or use one of the
* predefined migrators in {@link SwaggerMigrators}.
*
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11AllowableValuesMigrator.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11AllowableValuesMigrator.java
index b281f1bd89..4ac47f487c 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11AllowableValuesMigrator.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11AllowableValuesMigrator.java
@@ -14,11 +14,11 @@
/**
* Patch a 1.1 {@code allowableValues} into a 1.2 {@code enum}
- *
+ *
* {@code allowableValues} is an object which has at least one {@code
* valueType} member, whose value is a JSON String. If this string is {@code
* "LIST"}, then it is replaced by an {@code enum}, as in:
- *
+ *
*
* {
* "allowableValues": {
@@ -27,15 +27,15 @@
* }
* }
*
- *
+ *
* which will become:
- *
+ *
*
* {
* "enum": [ "a", "b", "c" ]
* }
*
- *
+ *
* Another possible value is {@code "range[]"}, however this migrator does
* not handle this case (yet?).
*/
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11ResourceListingMigrator.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11ResourceListingMigrator.java
index 4a1f1a2511..0d7d704815 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11ResourceListingMigrator.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11ResourceListingMigrator.java
@@ -32,9 +32,9 @@ public final class V11ResourceListingMigrator
/**
* Check the validity of a "basePath" argument at the root of a resource
* listing
- *
+ *
* A {@code basePath} is valid if it obeys the following conditions:
- *
+ *
*
* it is an absolute URI;
* its scheme is {@code http} or {@code https};
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11TypeMigrator.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11TypeMigrator.java
index 89d703005b..527571fc6a 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11TypeMigrator.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/V11TypeMigrator.java
@@ -18,15 +18,15 @@
/**
* Patch a 1.1 dataType into a 1.2 type
- *
+ *
* Several Swagger objects have the possibility of a data type; as such, JSON
* Schema validation currently cannot really limit the object members present,
* not without the "strictProperties" and "merge" proposals of draft v5.
- *
+ *
* The schema validation performed is therefore extremely simple: we only
* check that a {@code dataType} field is present, check that its value is one
* of the allowed values, and patch the node.
- *
+ *
* If {@code dataType} is not a known primitive, it is considered to be a
* v1.2 {@code $ref}.
*/
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/resourcelisting/PathAppenderMigrator.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/resourcelisting/PathAppenderMigrator.java
index 904dde8712..d301bee20f 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/resourcelisting/PathAppenderMigrator.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/migrate/resourcelisting/PathAppenderMigrator.java
@@ -11,7 +11,7 @@
/**
* Append a base path to individual API objects
- *
+ *
* See issue #4 on GitHub .
*/
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/MutableJsonTree.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/MutableJsonTree.java
index c82f9cb2d4..c0536c97fa 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/MutableJsonTree.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/MutableJsonTree.java
@@ -16,15 +16,15 @@
/**
* A mutable JSON tree with traversal capabilities
- *
+ *
* Navigation through the tree is done using {@link JsonPointer}s.
- *
+ *
* Note that {@link JsonNode} is mutable . This means that at init
* time we make a copy of the node given as argument (using {@link
* JsonNode#deepCopy()}, but after that all nodes returned by {@link
* #getCurrentNode()} are mutable. Changes you make to the returned node
* therefore will be reflected in the result.
- *
+ *
* While you can do that, it is advised that you use {@link SwaggerMigrator}s
* instead and make use of the {@link #applyMigrator(SwaggerMigrator)} and
* {@link #applyMigratorToElements(SwaggerMigrator)} methods.
@@ -48,7 +48,7 @@ public MutableJsonTree(final JsonNode node) {
/**
* Absolute pointer change
- *
+ *
* The new current node will be the node at this pointer starting from
* the base node.
*
@@ -62,7 +62,7 @@ public void setPointer(final JsonPointer pointer) {
/**
* Relative pointer change
- *
+ *
* The pointer in argument is appended to the current pointer (using
* {@link JsonPointer#append(JsonPointer)}) and the current node is set
* accordingly.
@@ -84,7 +84,7 @@ private void doSetPointer(final JsonPointer pointer) {
/**
* Return the base node
- *
+ *
* The "base node" here means the (potentially) altered copy of the node
* supplied as the constructor argument.
*
@@ -105,7 +105,7 @@ public JsonNode getCurrentNode() {
/**
* Apply a JSON Patch to the current node
- *
+ *
* This will turn the patch into a {@link SwaggerMigrator} using {@link
* SwaggerMigrators#fromPatch(JsonPatch)} and call {@link
* #applyMigrator(SwaggerMigrator)}.
@@ -121,7 +121,7 @@ public void applyPatch(final JsonPatch patch)
/**
* Apply a migrator to the node at the current pointer
- *
+ *
* It is assumed here that the current node is a JSON Object.
*
* @param migrator the migrator to apply
@@ -151,7 +151,7 @@ public void applyMigrator(final SwaggerMigrator migrator)
/**
* Apply a migrator to all elements of the array at the current pointer
- *
+ *
* Note that if the migrator fails to apply to at least one element, the
* original array is left untouched; its elements are replaced if and only
* if the migrator applies successfully to all elements.
@@ -178,7 +178,7 @@ public void applyMigratorToElements(final SwaggerMigrator migrator)
/**
* Apply a JSON Patch to all elements of a JSON Array
- *
+ *
* This will wrap the patch into a {@link SwaggerMigrator} using {@link
* SwaggerMigrators#fromPatch(JsonPatch)} and call {@link
* #applyMigratorToElements(SwaggerMigrator)}.
diff --git a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/SwaggerMigrators.java b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/SwaggerMigrators.java
index 4b13606c47..94531f2f36 100644
--- a/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/SwaggerMigrators.java
+++ b/modules/swagger-compat-spec-parser/src/main/java/io/swagger/transform/util/SwaggerMigrators.java
@@ -25,7 +25,7 @@ public final class SwaggerMigrators {
/**
* Return a migrator converting object member values to JSON Strings
- *
+ *
* Note that this will only work if member values are
* not containers (ie, JSON Arrays or Objects).
*
@@ -42,7 +42,7 @@ public static SwaggerMigrator membersToString(
/**
* Return a migrator applying a JSON Patch
- *
+ *
* The JSON Patch must be deserialized at this point. You can also load
* one from the classpath using {@link #patchFromResource(String)}.
*
@@ -69,7 +69,7 @@ public JsonNode migrate(@Nonnull final JsonNode input)
/**
* Return a migrator renaming object members
- *
+ *
* Note that this migrator will not fail if the member to rename does not
* exists; however it will fail if the target
* member already exists in the target JSON Object.
@@ -129,9 +129,9 @@ public static SwaggerMigrator patchFromResource(final String resourcePath) {
/**
* Migrator converting object member values to JSON Strings
- *
+ *
* Important notes:
- *
+ *
*
* this migrator will fail if at least one specified member has a
* "container" value (ie, the value is a JSON Array or an Objet);
diff --git a/modules/swagger-parser/pom.xml b/modules/swagger-parser/pom.xml
index b6bf9f9aaa..e06bfa186d 100644
--- a/modules/swagger-parser/pom.xml
+++ b/modules/swagger-parser/pom.xml
@@ -14,6 +14,18 @@
jar
swagger-parser
+
+ org.testng
+ testng
+ ${testng-version}
+ test
+
+
+ org.jmockit
+ jmockit
+ ${jmockit-version}
+ test
+
io.swagger
swagger-core
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java b/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java
new file mode 100644
index 0000000000..a79f9ce886
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/ResolverCache.java
@@ -0,0 +1,163 @@
+package io.swagger.parser;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import io.swagger.models.Swagger;
+import io.swagger.models.auth.AuthorizationValue;
+import io.swagger.models.refs.RefConstants;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.util.DeserializationUtils;
+import io.swagger.parser.util.RefUtils;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A class that caches values that have been loaded so we don't have to repeat
+ * expensive operations like:
+ * 1) reading a remote URL with authorization (e.g. using RemoteURL.java)
+ * 2) reading the contents of a file into memory
+ * 3) extracting a sub object from a json/yaml tree
+ * 4) de-serializing json strings into objects
+ */
+public class ResolverCache {
+
+ private static final Pattern PARAMETER_PATTERN = Pattern.compile("^" + RefConstants.INTERNAL_PARAMETER_PREFIX + "(?\\S+)");
+ private static final Pattern DEFINITION_PATTERN = Pattern.compile("^" + RefConstants.INTERNAL_DEFINITION_PREFIX + "(?\\S+)");
+
+ private final Swagger swagger;
+ private final List auths;
+ private final Path parentDirectory;
+ private Map resolutionCache = new HashMap<>();
+ private Map externalFileCache = new HashMap<>();
+
+ /*
+ a map that stores original external references, and their associated renamed references
+ */
+ private Map renameCache = new HashMap<>();
+
+ public ResolverCache(Swagger swagger, List auths, String parentFileLocation) {
+ this.swagger = swagger;
+ this.auths = auths;
+
+ if(parentFileLocation != null) {
+ if(parentFileLocation.startsWith("http")) {
+ parentDirectory = null;
+ } else {
+ final Path path = Paths.get(parentFileLocation);
+ parentDirectory = path.getParent();
+ }
+ } else {
+ File file = new File(".");
+ parentDirectory = file.toPath();
+ }
+
+ }
+
+ public T loadRef(String ref, RefFormat refFormat, Class expectedType) {
+ if (refFormat == RefFormat.INTERNAL) {
+ //we don't need to go get anything for internal refs
+ return expectedType.cast(loadInternalRef(ref));
+ }
+
+ final String[] refParts = ref.split("#/");
+
+ if (refParts.length > 2) {
+ throw new RuntimeException("Invalid ref format: " + ref);
+ }
+
+ final String file = refParts[0];
+ final String definitionPath = refParts.length == 2 ? refParts[1] : null;
+
+ //we might have already resolved this ref, so check the resolutionCache
+ Object previouslyResolvedEntity = resolutionCache.get(ref);
+
+ if (previouslyResolvedEntity != null) {
+ T result = expectedType.cast(previouslyResolvedEntity);
+ return result;
+ }
+
+ //we have not resolved this particular ref
+ //but we may have already loaded the file or url in question
+ String contents = externalFileCache.get(file);
+
+ if (contents == null) {
+ contents = RefUtils.readExternalRef(file, refFormat, auths, parentDirectory);
+ externalFileCache.put(file, contents);
+ }
+
+ if (definitionPath == null) {
+ T result = DeserializationUtils.deserialize(contents, file, expectedType);
+ resolutionCache.put(ref, result);
+ return result;
+ }
+
+ //a definition path is defined, meaning we need to "dig down" through the JSON tree and get the desired entity
+ JsonNode tree = DeserializationUtils.deserializeIntoTree(contents, file);
+
+ String[] jsonPathElements = definitionPath.split("/");
+ for (String jsonPathElement : jsonPathElements) {
+ tree = tree.get(jsonPathElement);
+ //if at any point we do find an element we expect, print and error and abort
+ if (tree == null) {
+ throw new RuntimeException("Could not find " + definitionPath + " in contents of " + file);
+ }
+ }
+
+ T result = DeserializationUtils.deserialize(tree, file, expectedType);
+ resolutionCache.put(ref, result);
+
+ return result;
+ }
+
+ private Object loadInternalRef(String ref) {
+
+ Object result = getFromMap(ref, swagger.getParameters(), PARAMETER_PATTERN);
+
+ if (result == null) {
+ result = getFromMap(ref, swagger.getDefinitions(), DEFINITION_PATTERN);
+ }
+
+ return result;
+
+ }
+
+ private Object getFromMap(String ref, Map map, Pattern pattern) {
+ final Matcher parameterMatcher = pattern.matcher(ref);
+
+ if (parameterMatcher.matches()) {
+ final String paramName = parameterMatcher.group("name");
+
+ if (map != null) {
+ return map.get(paramName);
+ }
+ }
+ return null;
+ }
+
+ public String getRenamedRef(String originalRef) {
+ return renameCache.get(originalRef);
+ }
+
+ public void putRenamedRef(String originalRef, String newRef) {
+ renameCache.put(originalRef, newRef);
+ }
+
+ public Map getResolutionCache() {
+ return Collections.unmodifiableMap(resolutionCache);
+ }
+
+ public Map getExternalFileCache() {
+ return Collections.unmodifiableMap(externalFileCache);
+ }
+
+ public Map getRenameCache() {
+ return Collections.unmodifiableMap(renameCache);
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java b/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java
index 7f3f336dd9..204b5d8ff9 100644
--- a/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerParser.java
@@ -26,7 +26,7 @@ public Swagger read(String location, List auths, boolean res
try {
output = new Swagger20Parser().read(location, auths);
if (output != null) {
- return new SwaggerResolver().resolve(output, auths);
+ return new SwaggerResolver(output, auths, location).resolve();
}
} catch (IOException e) {
// continue;
@@ -56,7 +56,7 @@ public Swagger parse(String swaggerAsString, List auths) {
try {
output = new Swagger20Parser().parse(swaggerAsString);
if (output != null) {
- return new SwaggerResolver().resolve(output, auths);
+ return new SwaggerResolver(output, auths, null).resolve();
}
} catch (IOException e) {
// continue;
@@ -80,7 +80,7 @@ public Swagger read(JsonNode node, boolean resolve) {
output = new Swagger20Parser().read(node);
if (output != null) {
if(resolve) {
- return new SwaggerResolver().resolve(output, new ArrayList());
+ return new SwaggerResolver(output, new ArrayList()).resolve();
}
else {
return output;
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerResolver.java b/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerResolver.java
index e476a33e63..f908fee9c3 100644
--- a/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerResolver.java
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/SwaggerResolver.java
@@ -1,332 +1,44 @@
package io.swagger.parser;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-import io.swagger.models.ArrayModel;
-import io.swagger.models.Model;
-import io.swagger.models.ModelImpl;
-import io.swagger.models.Operation;
-import io.swagger.models.Path;
-import io.swagger.models.RefModel;
-import io.swagger.models.Response;
-import io.swagger.models.Swagger;
+import io.swagger.models.*;
import io.swagger.models.auth.AuthorizationValue;
-import io.swagger.models.parameters.BodyParameter;
-import io.swagger.models.parameters.Parameter;
-import io.swagger.models.parameters.RefParameter;
-import io.swagger.models.properties.ArrayProperty;
-import io.swagger.models.properties.MapProperty;
-import io.swagger.models.properties.Property;
-import io.swagger.models.properties.RefProperty;
-import io.swagger.parser.util.RemoteUrl;
-import io.swagger.util.Json;
-import io.swagger.util.Yaml;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import io.swagger.parser.processors.DefinitionsProcessor;
+import io.swagger.parser.processors.ModelProcessor;
+import io.swagger.parser.processors.PathsProcessor;
-import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
+/**
+ *
+ */
public class SwaggerResolver {
- protected Swagger swagger;
- protected Map> resolutionMap = new HashMap>();
- protected ResolverOptions opts;
- Logger LOGGER = LoggerFactory.getLogger(SwaggerResolver.class);
-
- public SwaggerResolver() {
- }
- public SwaggerResolver(ResolverOptions opts) {
- this.opts = opts;
- }
-
- public Swagger resolve(Swagger swagger, List auths) {
- if (swagger == null) {
- return null;
- }
+ private final Swagger swagger;
+ private final ResolverCache cache;
+ private final PathsProcessor pathProcessor;
+ private final DefinitionsProcessor definitionsProcessor;
+ public SwaggerResolver(Swagger swagger, List auths, String parentFileLocation) {
this.swagger = swagger;
-
- // models
- detectModelRefs();
-
- // operations
- detectOperationRefs();
-
- applyResolutions(auths);
- return this.swagger;
+ this.cache = new ResolverCache(swagger, auths, parentFileLocation);
+ definitionsProcessor = new DefinitionsProcessor(cache, swagger);
+ pathProcessor = new PathsProcessor(cache, swagger);
}
- public void applyResolutions(List auths) {
- // hosts to call
- Map> hostToObjectMap = new HashMap>();
-
- for (String path : resolutionMap.keySet()) {
- String[] parts = path.split("#");
- if (parts.length == 2) {
- String host = parts[0];
- String definitionPath = parts[1];
- List objectList = hostToObjectMap.get(host);
- if (objectList == null) {
- objectList = new ArrayList();
- hostToObjectMap.put(host, objectList);
- }
- List contexts = resolutionMap.get(path);
- for (ResolutionContext ctx : contexts) {
- Object mapping = ctx.object;
- Object target = ctx.parent;
- try {
- String contents = null;
- if (host.startsWith("http")) {
- contents = new RemoteUrl().urlToString(host, auths);
- } else {
- contents = Json.mapper().writeValueAsString(swagger);
- }
- JsonNode location = null;
- String locationName = null;
- if (contents != null) {
- ObjectMapper mapper;
- if (contents.trim().startsWith("{")) {
- mapper = Json.mapper();
- } else {
- mapper = Yaml.mapper();
- }
- location = mapper.readTree(contents);
- String[] objectPath = definitionPath.split("/");
- for (String objectPathPart : objectPath) {
- LOGGER.debug("getting part " + objectPathPart);
- if (objectPathPart.length() > 0 && location != null) {
- location = location.get(objectPathPart);
- locationName = objectPathPart;
- }
- }
- }
- if (location != null) {
- // convert the node to the proper type
- if (mapping instanceof Property) {
- Model model = Json.mapper().convertValue(location, Model.class);
- if (mapping instanceof RefProperty) {
- RefProperty ref = (RefProperty) mapping;
- ref.set$ref(locationName);
- swagger.addDefinition(locationName, model);
- }
- } else if (target instanceof Parameter) {
- if (mapping instanceof RefModel) {
- Model model = Json.mapper().convertValue(location, Model.class);
- RefModel ref = (RefModel) mapping;
- ref.set$ref(locationName);
- swagger.addDefinition(locationName, model);
- }
- } else if (target instanceof Operation) {
-
- // get the operation position
- Operation operation = (Operation) target;
- int position = 0;
- for (Parameter param : operation.getParameters()) {
-
- if (param instanceof RefParameter) {
- RefParameter ref = (RefParameter) param;
- if (ref.getSimpleRef().equals(locationName)) {
- // found a match!
- Parameter remoteParam = Json.mapper().convertValue(location, Parameter.class);
- operation.getParameters().set(position, remoteParam);
- }
- }
- position += 1;
- }
- }
- }
- } catch (Exception e) {
- // failed to get it
- e.printStackTrace();
- }
- }
- }
- }
+ public SwaggerResolver(Swagger swagger, List auths) {
+ this(swagger, auths, null);
}
- public void detectOperationRefs() {
- Map paths = swagger.getPaths();
- if (paths == null) {
- return;
- }
-
- for (String pathName : paths.keySet()) {
- Path path = paths.get(pathName);
- List operations = path.getOperations();
- for (Operation operation : operations) {
- if (operation.getParameters() != null) {
- for (Parameter parameter : operation.getParameters()) {
- if (parameter instanceof BodyParameter) {
- BodyParameter bp = (BodyParameter) parameter;
- if (bp.getSchema() != null && bp.getSchema() instanceof RefModel) {
- RefModel ref = (RefModel) bp.getSchema();
- String key = ref.get$ref();
- if (key.startsWith("http")) {
- LOGGER.debug("added reference to " + key);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, bp, "ref"));
- resolutionMap.put(key, m);
- }
- }
- } else if (parameter instanceof RefParameter) {
- RefParameter ref = (RefParameter) parameter;
- String key = ref.get$ref();
- LOGGER.debug("added reference to " + ref);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, operation, "inline"));
- resolutionMap.put(key, m);
- }
- }
- }
- if (operation.getResponses() != null) {
- for (String responseCode : operation.getResponses().keySet()) {
- Response response = operation.getResponses().get(responseCode);
- if (response.getSchema() != null) {
- Property schema = response.getSchema();
- if (schema instanceof RefProperty) {
- RefProperty ref = (RefProperty) schema;
- String key = ref.get$ref();
-
- if (key != null && key.startsWith("http")) {
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, response, "ref"));
- resolutionMap.put(key, m);
- }
- }
- else if (schema instanceof ArrayProperty) {
- Property item = ((ArrayProperty)schema).getItems();
- if (item instanceof RefProperty) {
- RefProperty ref = (RefProperty) item;
- String key = ref.get$ref();
-
- if (key != null && key.startsWith("http")) {
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, schema, "ref"));
- resolutionMap.put(key, m);
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- public void detectModelRefs() {
- Map models = swagger.getDefinitions();
- if (models != null) {
- for (String modelName : models.keySet()) {
- LOGGER.debug("looking at " + modelName);
- Model model = models.get(modelName);
- if (model instanceof RefModel) {
- RefModel ref = (RefModel) model;
- String key = ref.get$ref();
- if (key != null && key.startsWith("http")) {
- LOGGER.debug("added reference to " + key);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, swagger.getDefinitions(), "ref"));
- resolutionMap.put(key, m);
- }
- } else if (model instanceof ArrayModel) {
- ArrayModel arrayModel = (ArrayModel) model;
- if (arrayModel.getItems() != null && arrayModel.getItems() instanceof RefProperty) {
- RefProperty ref = (RefProperty) arrayModel.getItems();
- String key = ref.get$ref();
- if (key != null && key.startsWith("http")) {
- LOGGER.debug("added reference to " + key);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, swagger.getDefinitions(), "ref"));
- resolutionMap.put(key, m);
- }
- }
- } else if (model instanceof ModelImpl) {
- ModelImpl impl = (ModelImpl) model;
- Map properties = impl.getProperties();
- if (properties != null) {
- for (String propertyName : properties.keySet()) {
- Property property = properties.get(propertyName);
- if (property instanceof RefProperty) {
- RefProperty ref = (RefProperty) property;
- String key = ref.get$ref();
- if (key != null && key.startsWith("http")) {
- LOGGER.debug("added reference to " + key);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, impl, "ref"));
- resolutionMap.put(key, m);
- }
- } else if (property instanceof ArrayProperty) {
- ArrayProperty arrayProperty = (ArrayProperty) property;
- if (arrayProperty.getItems() != null && arrayProperty.getItems() instanceof RefProperty) {
- RefProperty ref = (RefProperty) arrayProperty.getItems();
- String key = ref.get$ref();
- if (key != null && key.startsWith("http")) {
- LOGGER.debug("added reference to " + key);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, arrayProperty, "ref"));
- resolutionMap.put(key, m);
- }
- }
- } else if (property instanceof MapProperty) {
- MapProperty mp = (MapProperty) property;
- if (mp.getAdditionalProperties() != null && mp.getAdditionalProperties() instanceof RefProperty) {
- RefProperty ref = (RefProperty) mp.getAdditionalProperties();
- String key = ref.get$ref();
- if (key != null && key.startsWith("http")) {
- LOGGER.debug("added reference to " + key);
- List m = resolutionMap.get(key);
- if (m == null) {
- m = new ArrayList();
- }
- m.add(new ResolutionContext(ref, mp, "ref"));
- resolutionMap.put(key, m);
- }
- }
- }
- }
- }
- }
- }
+ public Swagger resolve() {
+ if (swagger == null) {
+ return null;
}
- }
- static class ResolutionContext {
- private Object object, parent;
- private String scope;
+ pathProcessor.processPaths();
+ definitionsProcessor.processDefinitions();
- public ResolutionContext(Object object, Object parent, String scope) {
- this.object = object;
- this.parent = parent;
- this.scope = scope;
- }
+ return swagger;
}
-}
\ No newline at end of file
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/DefinitionsProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/DefinitionsProcessor.java
new file mode 100644
index 0000000000..369efc6fc8
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/DefinitionsProcessor.java
@@ -0,0 +1,55 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Model;
+import io.swagger.models.RefModel;
+import io.swagger.models.Swagger;
+import io.swagger.parser.ResolverCache;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+public class DefinitionsProcessor {
+ private final ResolverCache cache;
+ private final Swagger swagger;
+ private final ModelProcessor modelProcessor;
+
+ public DefinitionsProcessor(ResolverCache cache, Swagger swagger) {
+
+ this.cache = cache;
+ this.swagger = swagger;
+ modelProcessor = new ModelProcessor(cache, swagger);
+ }
+
+ public void processDefinitions() {
+ final Map definitions = swagger.getDefinitions();
+
+ if (definitions == null) {
+ return;
+ }
+
+ Set keySet = new HashSet<>();
+ keySet.addAll(definitions.keySet());
+
+ for (String modelName : keySet) {
+ final Model model = definitions.get(modelName);
+
+ String originalRef = model instanceof RefModel ? ((RefModel) model).get$ref() : null;
+
+ modelProcessor.processModel(model);
+
+ //if we process a RefModel here, in the #/definitions table, we want to overwrite it with the referenced value
+ if (model instanceof RefModel) {
+ final String renamedRef = cache.getRenamedRef(originalRef);
+
+ if (renamedRef != null) {
+ //we definitely resolved the referenced and shoved it in the definitions map
+ final Model resolvedModel = definitions.remove(renamedRef);
+ definitions.put(modelName, resolvedModel);
+ }
+
+ }
+ }
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ExternalRefProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ExternalRefProcessor.java
new file mode 100644
index 0000000000..0b127668ab
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ExternalRefProcessor.java
@@ -0,0 +1,63 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Model;
+import io.swagger.models.Swagger;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static io.swagger.parser.util.RefUtils.computeDefinitionName;
+import static io.swagger.parser.util.RefUtils.deconflictName;
+
+
+public final class ExternalRefProcessor {
+
+ private final ResolverCache cache;
+ private final Swagger swagger;
+
+ public ExternalRefProcessor(ResolverCache cache, Swagger swagger) {
+ this.cache = cache;
+ this.swagger = swagger;
+ }
+
+ public String processRefToExternalDefinition(String $ref, RefFormat refFormat) {
+ final Model model = cache.loadRef($ref, refFormat, Model.class);
+
+ String newRef;
+
+ Map definitions = swagger.getDefinitions();
+
+ if (definitions == null) {
+ definitions = new HashMap<>();
+ }
+
+ final String possiblyConflictingDefinitionName = computeDefinitionName($ref);
+
+ final Model existingModel = definitions.get(possiblyConflictingDefinitionName);
+
+ if (existingModel != null) {
+
+ //so this is either a conflict, or another reference to something we have previously renamed
+ final String previouslyRenamedRef = cache.getRenamedRef($ref);
+ if (previouslyRenamedRef != null) {
+ //this is an additional reference to something we have renamed once
+ newRef = previouslyRenamedRef;
+ } else {
+ //this is a conflict
+ String deconflictedName = deconflictName(possiblyConflictingDefinitionName, definitions);
+ cache.putRenamedRef($ref, deconflictedName);
+ newRef = deconflictedName;
+ swagger.addDefinition(deconflictedName, model);
+ }
+
+ } else {
+ newRef = possiblyConflictingDefinitionName;
+ cache.putRenamedRef($ref, newRef);
+ swagger.addDefinition(newRef, model);
+ }
+
+ return newRef;
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ModelProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ModelProcessor.java
new file mode 100644
index 0000000000..cda0864faa
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ModelProcessor.java
@@ -0,0 +1,101 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.ArrayModel;
+import io.swagger.models.ComposedModel;
+import io.swagger.models.Model;
+import io.swagger.models.ModelImpl;
+import io.swagger.models.RefModel;
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.Property;
+import io.swagger.parser.ResolverCache;
+
+import java.util.List;
+import java.util.Map;
+
+import static io.swagger.parser.util.RefUtils.isAnExternalRefFormat;
+
+
+public class ModelProcessor {
+ private final PropertyProcessor propertyProcessor;
+ private final ExternalRefProcessor externalRefProcessor;
+
+ public ModelProcessor(ResolverCache cache, Swagger swagger) {
+ this.propertyProcessor = new PropertyProcessor(cache, swagger);
+ this.externalRefProcessor = new ExternalRefProcessor(cache, swagger);
+ }
+
+ public void processModel(Model model) {
+ if (model == null) {
+ return;
+ }
+
+ if (model instanceof RefModel) {
+ processRefModel((RefModel) model);
+ } else if (model instanceof ArrayModel) {
+ processArrayModel((ArrayModel) model);
+ } else if (model instanceof ComposedModel) {
+ processComposedModel((ComposedModel) model);
+ } else if (model instanceof ModelImpl) {
+ processModelImpl((ModelImpl) model);
+ }
+ }
+
+ private void processModelImpl(ModelImpl modelImpl) {
+
+ final Map properties = modelImpl.getProperties();
+
+ if (properties == null) {
+ return;
+ }
+
+ for (Map.Entry propertyEntry : properties.entrySet()) {
+ final Property property = propertyEntry.getValue();
+ propertyProcessor.processProperty(property);
+ }
+
+ }
+
+ private void processComposedModel(ComposedModel composedModel) {
+
+ processModel(composedModel.getParent());
+ processModel(composedModel.getChild());
+
+ final List interfaces = composedModel.getInterfaces();
+ if (interfaces != null) {
+ for (RefModel model : interfaces) {
+ processRefModel(model);
+ }
+ }
+
+ }
+
+ private void processArrayModel(ArrayModel arrayModel) {
+
+ final Property items = arrayModel.getItems();
+
+ // ArrayModel has a properties map, but my reading of the swagger spec makes me think it should be ignored
+
+ if (items != null) {
+ propertyProcessor.processProperty(items);
+ }
+ }
+
+
+ private void processRefModel(RefModel refModel) {
+ /* if this is a URL or relative ref:
+ 1) we need to load it into memory.
+ 2) shove it into the #/definitions
+ 3) update the RefModel to point to its location in #/definitions
+ */
+
+ if (isAnExternalRefFormat(refModel.getRefFormat())) {
+ final String newRef = externalRefProcessor.processRefToExternalDefinition(refModel.get$ref(), refModel.getRefFormat());
+
+ if (newRef != null) {
+ refModel.set$ref(newRef);
+ }
+ }
+ }
+
+
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/OperationProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/OperationProcessor.java
new file mode 100644
index 0000000000..1c06173b54
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/OperationProcessor.java
@@ -0,0 +1,51 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Operation;
+import io.swagger.models.RefResponse;
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.parser.ResolverCache;
+
+import java.util.List;
+import java.util.Map;
+
+
+public class OperationProcessor {
+
+
+ private final ParameterProcessor parameterProcessor;
+ private final ResponseProcessor responseProcessor;
+ private final ResolverCache cache;
+
+ public OperationProcessor(ResolverCache cache, Swagger swagger) {
+ this.cache = cache;
+ parameterProcessor = new ParameterProcessor(cache, swagger);
+ responseProcessor = new ResponseProcessor(cache, swagger);
+ }
+
+ public void processOperation(Operation operation) {
+ final List processedOperationParameters = parameterProcessor.processParameters(operation.getParameters());
+ operation.setParameters(processedOperationParameters);
+
+ final Map responses = operation.getResponses();
+
+ if (responses != null) {
+ for (String responseCode : responses.keySet()) {
+ Response response = responses.get(responseCode);
+
+ if (response instanceof RefResponse) {
+ RefResponse refResponse = (RefResponse) response;
+ Response resolvedResponse = cache.loadRef(refResponse.get$ref(), refResponse.getRefFormat(), Response.class);
+
+ if (resolvedResponse != null) {
+ response = resolvedResponse;
+ responses.put(responseCode, resolvedResponse);
+ }
+ }
+ responseProcessor.processResponse(response);
+ }
+ }
+ }
+
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ParameterProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ParameterProcessor.java
new file mode 100644
index 0000000000..d2da2a939d
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ParameterProcessor.java
@@ -0,0 +1,53 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Model;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.BodyParameter;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.parameters.RefParameter;
+import io.swagger.parser.ResolverCache;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+public class ParameterProcessor {
+
+ private final ResolverCache cache;
+ private final ModelProcessor modelProcessor;
+
+
+ public ParameterProcessor(ResolverCache cache, Swagger swagger) {
+ this.cache = cache;
+ this.modelProcessor = new ModelProcessor(cache, swagger);
+ }
+
+ public List processParameters(List parameters) {
+
+ if (parameters == null) {
+ return null;
+ }
+
+ final List incomingParameterList = parameters;
+ final List processedPathLevelParameters = new ArrayList<>();
+
+ for (Parameter parameter : incomingParameterList) {
+
+ if (parameter instanceof RefParameter) {
+ RefParameter refParameter = (RefParameter) parameter;
+ final Parameter resolvedParameter = cache.loadRef(refParameter.get$ref(), refParameter.getRefFormat(), Parameter.class);
+ parameter = resolvedParameter;
+ }
+
+ if (parameter instanceof BodyParameter) {
+ BodyParameter bodyParameter = (BodyParameter) parameter;
+ final Model schema = bodyParameter.getSchema();
+ modelProcessor.processModel(schema);
+ }
+
+ processedPathLevelParameters.add(parameter);
+
+ }
+ return processedPathLevelParameters;
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/PathsProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/PathsProcessor.java
new file mode 100644
index 0000000000..d5979ef730
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/PathsProcessor.java
@@ -0,0 +1,62 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.HttpMethod;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.RefPath;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.parser.ResolverCache;
+
+import java.util.List;
+import java.util.Map;
+
+
+public class PathsProcessor {
+
+ private final Swagger swagger;
+ private final ResolverCache cache;
+ private final ParameterProcessor parameterProcessor;
+ private final OperationProcessor operationProcessor;
+
+ public PathsProcessor(ResolverCache cache, Swagger swagger) {
+ this.swagger = swagger;
+ this.cache = cache;
+ parameterProcessor = new ParameterProcessor(cache, swagger);
+ operationProcessor = new OperationProcessor(cache, swagger);
+ }
+
+ public void processPaths() {
+ final Map pathMap = swagger.getPaths();
+
+ if (pathMap == null) {
+ return;
+ }
+
+ for (String pathStr : pathMap.keySet()) {
+ Path path = pathMap.get(pathStr);
+
+ if (path instanceof RefPath) {
+ RefPath refPath = (RefPath) path;
+ Path resolvedPath = cache.loadRef(refPath.get$ref(), refPath.getRefFormat(), Path.class);
+
+ if (resolvedPath != null) {
+ //we need to put the resolved path into swagger object
+ swagger.path(pathStr, resolvedPath);
+ path = resolvedPath;
+ }
+ }
+
+ //at this point we can process this path
+ final List processedPathParameters = parameterProcessor.processParameters(path.getParameters());
+ path.setParameters(processedPathParameters);
+
+ final Map operationMap = path.getOperationMap();
+
+ for (HttpMethod httpMethod : operationMap.keySet()) {
+ Operation operation = operationMap.get(httpMethod);
+ operationProcessor.processOperation(operation);
+ }
+ }
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/PropertyProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/PropertyProcessor.java
new file mode 100644
index 0000000000..a0a3c67d4f
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/PropertyProcessor.java
@@ -0,0 +1,53 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.Property;
+import io.swagger.models.properties.RefProperty;
+import io.swagger.parser.ResolverCache;
+
+import static io.swagger.parser.util.RefUtils.isAnExternalRefFormat;
+
+public class PropertyProcessor {
+
+ private final ExternalRefProcessor externalRefProcessor;
+
+ public PropertyProcessor(ResolverCache cache, Swagger swagger) {
+ externalRefProcessor = new ExternalRefProcessor(cache, swagger);
+ }
+
+ public void processProperty(Property property) {
+ if (property instanceof RefProperty) {
+ processRefProperty((RefProperty) property);
+ } else if (property instanceof ArrayProperty) {
+ processArrayProperty((ArrayProperty) property);
+ } else if (property instanceof MapProperty) {
+ processMapProperty((MapProperty) property);
+ }
+ }
+
+ private void processRefProperty(RefProperty refProperty) {
+ if (isAnExternalRefFormat(refProperty.getRefFormat())) {
+ final String newRef = externalRefProcessor.processRefToExternalDefinition(refProperty.get$ref(), refProperty.getRefFormat());
+
+ if (newRef != null) {
+ refProperty.set$ref(newRef);
+ }
+ }
+ }
+
+ private void processMapProperty(MapProperty property) {
+ final Property additionalProperties = property.getAdditionalProperties();
+ if (additionalProperties != null) {
+ processProperty(additionalProperties);
+ }
+ }
+
+ private void processArrayProperty(ArrayProperty property) {
+ final Property items = property.getItems();
+ if (items != null) {
+ processProperty(items);
+ }
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ResponseProcessor.java b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ResponseProcessor.java
new file mode 100644
index 0000000000..168d883e1b
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/processors/ResponseProcessor.java
@@ -0,0 +1,32 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.Property;
+import io.swagger.parser.ResolverCache;
+
+import java.util.Map;
+
+public class ResponseProcessor {
+
+ private final PropertyProcessor propertyProcessor;
+
+ public ResponseProcessor(ResolverCache cache, Swagger swagger) {
+ propertyProcessor = new PropertyProcessor(cache, swagger);
+ }
+
+ public void processResponse(Response response) {
+ //process the response body
+ final Property schema = response.getSchema();
+
+ if (schema != null) {
+ propertyProcessor.processProperty(schema);
+ }
+
+ /* intentionally ignoring the response headers, even those these were modelled as a
+ Map they should never have a $ref because what does it mean to have a
+ complex object in an HTTP header?
+ */
+
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java b/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java
new file mode 100644
index 0000000000..6455f64791
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/util/DeserializationUtils.java
@@ -0,0 +1,53 @@
+package io.swagger.parser.util;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.util.Json;
+import io.swagger.util.Yaml;
+
+import java.io.IOException;
+
+/**
+ * Created by russellb337 on 7/14/15.
+ */
+public class DeserializationUtils {
+ public static JsonNode deserializeIntoTree(String contents, String fileOrHost) {
+ JsonNode result;
+
+ try {
+ if (fileOrHost.endsWith(".yaml")) {
+ result = Yaml.mapper().readTree(contents);
+ } else {
+ result = Json.mapper().readTree(contents);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("An exception was thrown while trying to deserialize the contents of " + fileOrHost + " into a JsonNode tree", e);
+ }
+
+ return result;
+ }
+
+ public static T deserialize(Object contents, String fileOrHost, Class expectedType) {
+ T result;
+
+ ObjectMapper mapper;
+
+ if(fileOrHost.endsWith(".yaml")) {
+ mapper = Yaml.mapper();
+ } else {
+ mapper = Json.mapper();
+ }
+
+ try {
+ if (contents instanceof String) {
+ result = mapper.readValue((String) contents, expectedType);
+ } else {
+ result = mapper.convertValue(contents, expectedType);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("An exception was thrown while trying to deserialize the contents of " + fileOrHost + " into type " + expectedType, e);
+ }
+
+ return result;
+ }
+}
diff --git a/modules/swagger-parser/src/main/java/io/swagger/parser/util/RefUtils.java b/modules/swagger-parser/src/main/java/io/swagger/parser/util/RefUtils.java
new file mode 100644
index 0000000000..c17da06ea2
--- /dev/null
+++ b/modules/swagger-parser/src/main/java/io/swagger/parser/util/RefUtils.java
@@ -0,0 +1,89 @@
+package io.swagger.parser.util;
+
+import io.swagger.models.Model;
+import io.swagger.models.auth.AuthorizationValue;
+import io.swagger.models.refs.RefFormat;
+import org.apache.commons.io.IOUtils;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by russellb337 on 7/10/15.
+ */
+public class RefUtils {
+
+ public static String computeDefinitionName(String ref) {
+
+ final String[] refParts = ref.split("#/");
+
+ if (refParts.length > 2) {
+ throw new RuntimeException("Invalid ref format: " + ref);
+ }
+
+ final String file = refParts[0];
+ final String definitionPath = refParts.length == 2 ? refParts[1] : null;
+
+
+ String plausibleName;
+
+ if (definitionPath != null) { //the name will come from the last element of the definition path
+ final String[] jsonPathElements = definitionPath.split("/");
+ plausibleName = jsonPathElements[jsonPathElements.length - 1];
+ } else { //no definition path, so we must come up with a name from the file
+ final String[] filePathElements = file.split("/");
+ plausibleName = filePathElements[filePathElements.length - 1];
+
+ final String[] split = plausibleName.split("\\.");
+ plausibleName = split[0];
+ }
+
+ return plausibleName;
+ }
+
+ public static String deconflictName(String possiblyConflictingDefinitionName, Map definitions) {
+
+ String result = possiblyConflictingDefinitionName;
+ int count = 1;
+
+ while (definitions.containsKey(result)) {
+ result = possiblyConflictingDefinitionName + count;
+ count++;
+ }
+
+ return result;
+ }
+
+ public static boolean isAnExternalRefFormat(RefFormat refFormat) {
+ return refFormat == RefFormat.URL || refFormat == RefFormat.RELATIVE;
+ }
+
+ public static String readExternalRef(String file, RefFormat refFormat, List auths,
+ Path parentDirectory) {
+
+ if (!RefUtils.isAnExternalRefFormat(refFormat)) {
+ throw new RuntimeException("Ref is not external");
+ }
+
+ String result;
+
+ try {
+ if (refFormat == RefFormat.URL) {
+ result = RemoteUrl.urlToString(file, auths);
+ } else {
+ //its assumed to be a relative file ref
+ final Path pathToUse = parentDirectory.resolve(file).normalize();
+ result = IOUtils.toString(new FileInputStream(pathToUse.toString()));
+ }
+ } catch (Exception e) {
+ throw new RuntimeException("Unable to load " + refFormat + " ref: " + file, e);
+ }
+
+ return result;
+
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/JsonToYamlFileDuplicator.java b/modules/swagger-parser/src/test/java/io/swagger/parser/JsonToYamlFileDuplicator.java
new file mode 100644
index 0000000000..bafb7498e8
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/JsonToYamlFileDuplicator.java
@@ -0,0 +1,70 @@
+package io.swagger.parser;
+
+
+import com.fasterxml.jackson.databind.JsonNode;
+import io.swagger.parser.util.DeserializationUtils;
+import io.swagger.util.Yaml;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Iterator;
+
+public class JsonToYamlFileDuplicator {
+
+ public static void duplicateFilesInYamlFormat(String inputDirectoryStr, String outputDirectoryStr) {
+ Path outputDirectory = Paths.get(outputDirectoryStr);
+ Path inputDirectory = Paths.get(inputDirectoryStr);
+
+ deleteAndRecreateOutputDirectory(outputDirectory);
+
+ final Iterator fileIterator = FileUtils.iterateFiles(inputDirectory.toFile(), new String[]{"json"}, true);
+ while (fileIterator.hasNext()) {
+ File next = fileIterator.next();
+ System.out.println("Processing " + next);
+
+ processFile(next, inputDirectory, outputDirectory);
+ }
+
+ }
+
+ private static void processFile(File next, Path inputDirectory, Path outputDirectory) {
+ try {
+ String fileContents = IOUtils.toString(new FileInputStream(next));
+ fileContents = fileContents.replaceAll("\\.json", ".yaml");
+
+ final JsonNode jsonNode = DeserializationUtils.deserializeIntoTree(fileContents, next.toString());
+
+ final String yamlOutput = Yaml.mapper().writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode);
+
+
+ final String relativePath = "./" + next.toString().replace(inputDirectory.toString(), "").replace(".json", ".yaml");
+
+ final Path outputFile = outputDirectory.resolve(relativePath).normalize();
+ System.out.println(outputFile);
+
+ final File file = outputFile.toAbsolutePath().toFile();
+ FileUtils.forceMkdir(outputFile.getParent().toFile());
+ FileUtils.write(file, yamlOutput);
+
+ } catch (IOException e) {
+ throw new RuntimeException("Could not process file " + next, e);
+ }
+
+ }
+
+ private static void deleteAndRecreateOutputDirectory(Path outputDirectory) {
+ try {
+ FileUtils.deleteDirectory(outputDirectory.toFile());
+ outputDirectory.toFile().mkdirs();
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to delete directory: " + outputDirectory, e);
+ }
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/ResolverCacheTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/ResolverCacheTest.java
new file mode 100644
index 0000000000..6d1a3a1317
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/ResolverCacheTest.java
@@ -0,0 +1,238 @@
+package io.swagger.parser;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.JsonNodeFactory;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import io.swagger.models.Model;
+import io.swagger.models.Swagger;
+import io.swagger.models.auth.AuthorizationValue;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.util.DeserializationUtils;
+import io.swagger.parser.util.RefUtils;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.apache.commons.lang3.tuple.Pair;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.fail;
+
+public class ResolverCacheTest {
+
+ @Mocked
+ RefUtils refUtils;
+
+ @Mocked
+ DeserializationUtils deserializationUtils;
+
+ @Injectable
+ Swagger swagger;
+ @Injectable
+ List auths;
+
+
+ @Test
+ public void testLoadExternalRef_NoDefinitionPath(@Injectable final Model expectedResult) throws Exception {
+
+ final RefFormat format = RefFormat.URL;
+ final String ref = "http://my.company.com/path/to/file.json";
+ final String contentsOfExternalFile = "really good json";
+
+ new StrictExpectations() {{
+ RefUtils.readExternalRef(ref, format, auths, null);
+ times = 1;
+ result = contentsOfExternalFile;
+
+ DeserializationUtils.deserialize(contentsOfExternalFile, ref, Model.class);
+ times = 1;
+ result = expectedResult;
+ }};
+
+ ResolverCache cache = new ResolverCache(swagger, auths, "http://my.company.com/path/parent.json");
+
+ Model firstActualResult = cache.loadRef(ref, RefFormat.URL, Model.class);
+
+ assertEquals(contentsOfExternalFile, cache.getExternalFileCache().get(ref));
+ assertEquals(expectedResult, cache.getResolutionCache().get(ref));
+ assertEquals(expectedResult, firstActualResult);
+
+ //requesting the same ref a second time should not result in reading the external file again
+ Model secondActualResult = cache.loadRef(ref, format, Model.class);
+ assertEquals(expectedResult, secondActualResult);
+
+ }
+
+ @Test
+ public void testLoadExternalRef_TwoRefsFromSameFile(@Injectable final Model expectedResult1,
+ @Injectable final Model expectedResult2) throws Exception {
+
+ final RefFormat format = RefFormat.URL;
+ final String file = "http://my.company.com/path/to/file.json";
+ final String path1 = "#/hello/world/foo/bar";
+ final String path2 = "#/hello/world/this/that";
+ final String fullRef1 = file + path1;
+ final String fullRef2 = file + path2;
+ final String contentsOfExternalFile = "really good json";
+ final Pair nodePair = constructJsonTree("hello", "world", "foo", "bar");
+
+ ObjectNode parentNode = (ObjectNode) nodePair.getLeft();
+ ObjectNode intermediateNode = (ObjectNode) parentNode.get("hello").get("world");
+ final ObjectNode secondLeaf = intermediateNode.putObject("this").putObject("that");
+
+
+ new StrictExpectations() {{
+ RefUtils.readExternalRef(file, format, auths, null);
+ times = 1;
+ result = contentsOfExternalFile;
+
+ DeserializationUtils.deserializeIntoTree(contentsOfExternalFile, file);
+ times = 1;
+ result = nodePair.getLeft();
+
+ DeserializationUtils.deserialize(nodePair.getRight(), file, Model.class);
+ times = 1;
+ result = expectedResult1;
+
+ DeserializationUtils.deserializeIntoTree(contentsOfExternalFile, file);
+ times = 1;
+ result = nodePair.getLeft();
+
+ DeserializationUtils.deserialize(secondLeaf, file, Model.class);
+ times = 1;
+ result = expectedResult2;
+ }};
+
+ ResolverCache cache = new ResolverCache(swagger, auths, "http://my.company.com/path/parent.json");
+
+ Model firstRefResult = cache.loadRef(fullRef1, format, Model.class);
+ assertEquals(expectedResult1, cache.getResolutionCache().get(fullRef1));
+ assertEquals(expectedResult1, firstRefResult);
+
+ Model secondRefResult = cache.loadRef(fullRef2, format, Model.class);
+ assertEquals(expectedResult2, cache.getResolutionCache().get(fullRef2));
+ assertEquals(expectedResult2, secondRefResult);
+
+ assertEquals(contentsOfExternalFile, cache.getExternalFileCache().get(file));
+ }
+
+ @Test
+ public void testLoadExternalRef_WithDefinitionPath(@Injectable final Model expectedResult) throws Exception {
+
+ final RefFormat format = RefFormat.URL;
+ final String file = "http://my.company.com/path/to/file.json";
+ final String path = "#/hello/world/foo/bar";
+ final String fullRef = file + path;
+ final String contentsOfExternalFile = "really good json";
+ final Pair nodePair = constructJsonTree("hello", "world", "foo", "bar");
+
+ new StrictExpectations() {{
+ RefUtils.readExternalRef(file, format, auths, null);
+ times = 1;
+ result = contentsOfExternalFile;
+
+ DeserializationUtils.deserializeIntoTree(contentsOfExternalFile, file);
+ times = 1;
+ result = nodePair.getLeft();
+
+ DeserializationUtils.deserialize(nodePair.getRight(), file, Model.class);
+ times = 1;
+ result = expectedResult;
+ }};
+
+ ResolverCache cache = new ResolverCache(swagger, auths, "http://my.company.com/path/parent.json");
+ Model firstActualResult = cache.loadRef(fullRef, format, Model.class);
+
+ assertEquals(contentsOfExternalFile, cache.getExternalFileCache().get(file));
+ assertEquals(expectedResult, cache.getResolutionCache().get(fullRef));
+ assertEquals(expectedResult, firstActualResult);
+
+ //requesting the same ref a second time should not result in reading the external file again
+ Model secondActualResult = cache.loadRef(fullRef, format, Model.class);
+ assertEquals(expectedResult, secondActualResult);
+ }
+
+ @Test
+ public void testLoadExternalRef_WithInvalidDefinitionPath() throws Exception {
+
+ final RefFormat format = RefFormat.URL;
+ final String file = "http://my.company.com/path/to/file.json";
+ final String path = "hello/world/bar/foo";
+ final String fullRef = file + "#/" + path;
+ final String contentsOfExternalFile = "really good json";
+ final Pair nodePair = constructJsonTree("hello", "world", "foo", "bar");
+
+ new StrictExpectations() {{
+ RefUtils.readExternalRef(file, format, auths, null);
+ times = 1;
+ result = contentsOfExternalFile;
+
+ DeserializationUtils.deserializeIntoTree(contentsOfExternalFile, file);
+ times = 1;
+ result = nodePair.getLeft();
+
+ }};
+
+ ResolverCache cache = new ResolverCache(swagger, auths, "http://my.company.com/path/parent.json");
+
+ try {
+ cache.loadRef(fullRef, format, Model.class);
+ fail("Should have thrown an exception");
+ } catch(RuntimeException e) {
+ assertEquals("Could not find " + path + " in contents of " + file, e.getMessage());
+ }
+ }
+
+ @Test
+ public void testLoadInternalParameterRef(@Injectable Parameter mockedParameter) throws Exception {
+ Swagger swagger = new Swagger();
+ swagger.parameter("foo", mockedParameter);
+
+ ResolverCache cache = new ResolverCache(swagger, auths, null);
+ Parameter actualResult = cache.loadRef("#/parameters/foo", RefFormat.INTERNAL, Parameter.class);
+ assertEquals(actualResult, mockedParameter);
+
+ assertNull(cache.loadRef("#/parameters/bar", RefFormat.INTERNAL, Parameter.class));
+ assertNull(cache.loadRef("#/params/foo", RefFormat.INTERNAL, Parameter.class));
+ }
+
+ @Test
+ public void testLoadInternalDefinitionRef(@Injectable Model mockedModel) throws Exception {
+ Swagger swagger = new Swagger();
+ swagger.addDefinition("foo", mockedModel);
+
+ ResolverCache cache = new ResolverCache(swagger, auths, null);
+ Model actualResult = cache.loadRef("#/definitions/foo", RefFormat.INTERNAL, Model.class);
+ assertEquals(actualResult, mockedModel);
+
+ assertNull(cache.loadRef("#/definitions/bar", RefFormat.INTERNAL, Model.class));
+ assertNull(cache.loadRef("#/defs/bar", RefFormat.INTERNAL, Model.class));
+ }
+
+ @Test
+ public void testRenameCache() throws Exception {
+ ResolverCache cache = new ResolverCache(swagger, auths, null);
+
+ assertNull(cache.getRenamedRef("foo"));
+ cache.putRenamedRef("foo", "bar");
+ assertEquals(cache.getRenamedRef("foo"), "bar");
+ }
+
+ private Pair constructJsonTree(String... properties) {
+ JsonNodeFactory factory = new JsonNodeFactory(true);
+ final ObjectNode parent = factory.objectNode();
+ ObjectNode current = parent;
+
+ for (String property : properties) {
+ current = current.putObject(property);
+ }
+
+ current.put("key", "value");
+
+ return Pair.of((JsonNode) parent, (JsonNode) current);
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerParserTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerParserTest.java
new file mode 100644
index 0000000000..ffc2c251cf
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerParserTest.java
@@ -0,0 +1,121 @@
+package io.swagger.parser;
+
+import io.swagger.models.*;
+import io.swagger.models.parameters.*;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.RefProperty;
+import io.swagger.util.Yaml;
+import org.testng.annotations.Test;
+
+import java.util.List;
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+
+public class SwaggerParserTest {
+
+ @Test
+ public void testLoadRelativeFileTree_Json() throws Exception {
+ final Swagger swagger = doRelativeFileTest("src/test/resources/relative-file-references/json/parent.json");
+ //Json.mapper().writerWithDefaultPrettyPrinter().writeValue(new File("resolved.json"), swagger);
+ }
+
+ @Test
+ public void testLoadRelativeFileTree_Yaml() throws Exception {
+ JsonToYamlFileDuplicator.duplicateFilesInYamlFormat("src/test/resources/relative-file-references/json",
+ "src/test/resources/relative-file-references/yaml");
+ final Swagger swagger = doRelativeFileTest("src/test/resources/relative-file-references/yaml/parent.yaml");
+ //Yaml.pretty().writeValue(new File("resolved.yaml"), swagger);
+ System.out.println(Yaml.mapper().writeValueAsString(swagger));
+ }
+
+ private Swagger doRelativeFileTest(String location) {
+ SwaggerParser parser = new SwaggerParser();
+ final Swagger swagger = parser.read(location);
+
+
+
+ final Path path = swagger.getPath("/health");
+ assertEquals(path.getClass(), Path.class); //we successfully converted the RefPath to a Path
+
+ final List parameters = path.getParameters();
+ assertParamDetails(parameters, 0, QueryParameter.class, "param1", "query");
+ assertParamDetails(parameters, 1, HeaderParameter.class, "param2", "header");
+
+ final Operation operation = path.getGet();
+ final List operationParams = operation.getParameters();
+ assertParamDetails(operationParams, 0, PathParameter.class, "param3", "path");
+ assertParamDetails(operationParams, 1, HeaderParameter.class, "param4", "header");
+ assertParamDetails(operationParams, 2, BodyParameter.class, "body", "body");
+ final BodyParameter bodyParameter = (BodyParameter) operationParams.get(2);
+ assertEquals(((RefModel) bodyParameter.getSchema()).get$ref(), "#/definitions/health");
+
+ final Map responsesMap = operation.getResponses();
+
+ assertResponse(swagger, responsesMap, "200", "Health information from the server", "#/definitions/health");
+ assertResponse(swagger, responsesMap, "400", "Your request was not valid", "#/definitions/error");
+ assertResponse(swagger, responsesMap, "500", "An unexpected error occur during processing", "#/definitions/error");
+
+ final Map definitions = swagger.getDefinitions();
+ final ModelImpl refInDefinitions = (ModelImpl) definitions.get("refInDefinitions");
+
+ assertEquals(refInDefinitions.getDescription(), "The example model");
+ expectedPropertiesInModel(refInDefinitions, "foo", "bar");
+
+ final ArrayModel arrayModel = (ArrayModel) definitions.get("arrayModel");
+ final RefProperty arrayModelItems = (RefProperty) arrayModel.getItems();
+ assertEquals(arrayModelItems.get$ref(), "#/definitions/foo");
+
+ final ModelImpl fooModel = (ModelImpl) definitions.get("foo");
+ assertEquals(fooModel.getDescription(), "Just another model");
+ expectedPropertiesInModel(fooModel, "hello", "world");
+
+ final ComposedModel composedCat = (ComposedModel) definitions.get("composedCat");
+ final ModelImpl child = (ModelImpl) composedCat.getChild();
+ expectedPropertiesInModel(child, "huntingSkill", "prop2", "reflexes", "reflexMap");
+ final ArrayProperty reflexes = (ArrayProperty) child.getProperties().get("reflexes");
+ final RefProperty reflexItems = (RefProperty) reflexes.getItems();
+ assertEquals(reflexItems.get$ref(), "#/definitions/reflex");
+ assertTrue(definitions.containsKey(reflexItems.getSimpleRef()));
+
+ final MapProperty reflexMap = (MapProperty) child.getProperties().get("reflexMap");
+ final RefProperty reflexMapAdditionalProperties = (RefProperty) reflexMap.getAdditionalProperties();
+ assertEquals(reflexMapAdditionalProperties.get$ref(), "#/definitions/reflex");
+
+ final RefModel parent = (RefModel) composedCat.getParent();
+ assertEquals(parent.get$ref(), "#/definitions/pet");
+
+ assertEquals(composedCat.getInterfaces().size(), 1);
+ assertEquals(composedCat.getInterfaces().get(0).get$ref(), "#/definitions/foo1");
+
+ return swagger;
+ }
+
+ private void expectedPropertiesInModel(ModelImpl model, String... expectedProperties) {
+ assertEquals(model.getProperties().size(), expectedProperties.length);
+ for (String expectedProperty : expectedProperties) {
+ assertTrue(model.getProperties().containsKey(expectedProperty));
+ }
+ }
+
+ private void assertResponse(Swagger swagger, Map responsesMap, String responseCode,
+ String expectedDescription, String expectedSchemaRef) {
+ final Response response = responsesMap.get(responseCode);
+ final RefProperty schema = (RefProperty) response.getSchema();
+ assertEquals(response.getDescription(), expectedDescription);
+ assertEquals(schema.getClass(), RefProperty.class);
+ assertEquals(schema.get$ref(), expectedSchemaRef);
+ assertTrue(swagger.getDefinitions().containsKey(schema.getSimpleRef()));
+ }
+
+ private void assertParamDetails(List parameters, int index, Class> expectedType,
+ String expectedName, String expectedIn) {
+ final Parameter param1 = parameters.get(index);
+ assertEquals(param1.getClass(), expectedType);
+ assertEquals(param1.getName(), expectedName);
+ assertEquals(param1.getIn(), expectedIn);
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerResolverTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerResolverTest.java
new file mode 100644
index 0000000000..ee5ea61081
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/SwaggerResolverTest.java
@@ -0,0 +1,55 @@
+package io.swagger.parser;
+
+import io.swagger.models.Swagger;
+import io.swagger.models.auth.AuthorizationValue;
+import io.swagger.parser.processors.DefinitionsProcessor;
+import io.swagger.parser.processors.PathsProcessor;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+
+
+public class SwaggerResolverTest {
+
+ @Test
+ public void testSwaggerResolver(@Injectable final Swagger swagger,
+ @Injectable final List auths,
+ @Mocked final ResolverCache cache,
+ @Mocked final DefinitionsProcessor definitionsProcessor,
+ @Mocked final PathsProcessor pathsProcessor) throws Exception {
+
+ new StrictExpectations() {{
+ new ResolverCache(swagger, auths, null);
+ result = cache;
+ times = 1;
+
+ new DefinitionsProcessor(cache, swagger);
+ result = definitionsProcessor;
+ times=1;
+
+ new PathsProcessor(cache, swagger);
+ result = pathsProcessor;
+ times=1;
+
+ pathsProcessor.processPaths();
+ times=1;
+
+ definitionsProcessor.processDefinitions();
+ times=1;
+
+ }};
+
+ assertEquals(new SwaggerResolver(swagger, auths, null).resolve(), swagger);
+ }
+
+ @Test
+ public void testSwaggerResolver_NullSwagger() throws Exception {
+ assertNull(new SwaggerResolver(null, null, null).resolve());
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/DefinitionsProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/DefinitionsProcessorTest.java
new file mode 100644
index 0000000000..49ce45f042
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/DefinitionsProcessorTest.java
@@ -0,0 +1,103 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Model;
+import io.swagger.models.RefModel;
+import io.swagger.models.Swagger;
+import io.swagger.parser.ResolverCache;
+import mockit.*;
+import org.testng.annotations.Test;
+
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+
+public class DefinitionsProcessorTest {
+
+
+ @Mocked
+ ModelProcessor modelProcessor;
+
+ @Test
+ public void testDefinitionsProcessor(@Injectable final Model model1,
+ @Injectable final Model model2,
+ @Injectable final ResolverCache cache) throws Exception {
+
+ final Swagger swagger = new Swagger();
+ swagger.addDefinition("foo", model1);
+ swagger.addDefinition("bar", model2);
+
+
+ new Expectations() {{
+ new ModelProcessor(cache, swagger);
+ times = 1;
+ result = modelProcessor;
+ modelProcessor.processModel((Model) any);
+ times = 2;
+ }};
+
+ new DefinitionsProcessor(cache, swagger).processDefinitions();
+
+ new Verifications() {{
+ modelProcessor.processModel(model1);
+ modelProcessor.processModel(model2);
+ }};
+ }
+
+ @Test
+ public void testNoDefinitionsDefined(@Injectable final Swagger swagger,
+ @Injectable final ResolverCache cache) throws Exception {
+
+ new StrictExpectations() {{
+ new ModelProcessor(cache, swagger);
+ times = 1;
+ result = modelProcessor;
+ swagger.getDefinitions();
+ times = 1;
+ result = null;
+ }};
+
+ new DefinitionsProcessor(cache, swagger).processDefinitions();
+
+ new FullVerifications() {{
+ }};
+ }
+
+ @Test
+ public void testDefinitiosProcessor_RefModelInDefinitionsMap(
+ @Injectable final Model resolvedModel) throws Exception {
+ final Swagger swagger = new Swagger();
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefModel refModel = new RefModel(ref);
+ swagger.addDefinition("foo", refModel);
+
+ final MockUp mockup = new MockUp() {
+ @Mock(invocations = 1)
+ String getRenamedRef(String ref) {
+ swagger.getDefinitions().put("bar", resolvedModel);
+ return "bar";
+ }
+ };
+
+ final ResolverCache mockResolverCache = mockup.getMockInstance();
+
+
+ new StrictExpectations() {{
+ new ModelProcessor(mockResolverCache, swagger);
+ times = 1;
+ result = modelProcessor;
+
+ modelProcessor.processModel(refModel);
+ times = 1;
+ }};
+
+ new DefinitionsProcessor(mockResolverCache, swagger).processDefinitions();
+
+ new FullVerifications(){{}};
+
+ final Map definitions = swagger.getDefinitions();
+ assertEquals(definitions.size(), 1);
+
+ final Model foo = definitions.get("foo");
+ assertEquals(foo, resolvedModel);
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ExternalRefProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ExternalRefProcessorTest.java
new file mode 100644
index 0000000000..b54980673b
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ExternalRefProcessorTest.java
@@ -0,0 +1,115 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Model;
+import io.swagger.models.ModelImpl;
+import io.swagger.models.RefModel;
+import io.swagger.models.Swagger;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+import mockit.Injectable;
+import mockit.StrictExpectations;
+import org.testng.annotations.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+
+
+public class ExternalRefProcessorTest {
+
+ @Injectable
+ ResolverCache cache;
+
+ @Injectable
+ Swagger swagger;
+
+ @Test
+ public void testProcessRefToExternalDefinition_NoNameConflict(
+ @Injectable final Model mockedModel) throws Exception {
+
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefFormat refFormat = RefFormat.URL;
+
+ new StrictExpectations() {{
+ cache.loadRef(ref, refFormat, Model.class);
+ times = 1;
+ result = mockedModel;
+
+ swagger.getDefinitions();
+ times = 1;
+ result = null;
+
+ cache.putRenamedRef(ref, "bar");
+ swagger.addDefinition("bar", mockedModel); times=1;
+ }};
+
+ String newRef = new ExternalRefProcessor(cache, swagger).processRefToExternalDefinition(ref, refFormat);
+ assertEquals(newRef, "bar");
+ }
+
+
+ @Test
+ public void testProcessRefToExternalDefinition_NameConflict_FirstAppearance(
+ @Injectable final Model mockedModel) throws Exception {
+
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefFormat refFormat = RefFormat.URL;
+
+ final Map definitionsMap = new HashMap<>();
+ definitionsMap.put("bar", new ModelImpl());
+
+ final String expectedNewRef = "bar1";
+
+ new StrictExpectations() {{
+ cache.loadRef(ref, refFormat, Model.class);
+ times = 1;
+ result = mockedModel;
+
+ swagger.getDefinitions();
+ times = 1;
+ result = definitionsMap;
+
+ cache.getRenamedRef(ref);
+ times = 1;
+ result = null;
+
+ cache.putRenamedRef(ref, expectedNewRef); times=1;
+
+ swagger.addDefinition(expectedNewRef, mockedModel);
+ }};
+
+ String newRef = new ExternalRefProcessor(cache, swagger).processRefToExternalDefinition(ref, refFormat);
+ assertEquals(newRef, expectedNewRef);
+ }
+
+ @Test
+ public void testProcessRefToExternalDefinition_NameConflict_SecondAppearance(@Injectable final Model mockedModel) throws Exception {
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefFormat refFormat = RefFormat.URL;
+
+ final Map definitionsMap = new HashMap<>();
+ definitionsMap.put("bar", new ModelImpl());
+ definitionsMap.put("bar1", mockedModel);
+
+ final String expectedNewRef = "bar1";
+
+
+ new StrictExpectations() {{
+ cache.loadRef(ref, refFormat, Model.class);
+ times = 1;
+ result = mockedModel;
+
+ swagger.getDefinitions();
+ times = 1;
+ result = definitionsMap;
+
+ cache.getRenamedRef(ref);
+ times = 1;
+ result = expectedNewRef;
+ }};
+
+ String newRef = new ExternalRefProcessor(cache, swagger).processRefToExternalDefinition(ref, refFormat);
+ assertEquals(newRef, expectedNewRef);
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ModelProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ModelProcessorTest.java
new file mode 100644
index 0000000000..587dd4a4a2
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ModelProcessorTest.java
@@ -0,0 +1,153 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.*;
+import io.swagger.models.properties.Property;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+import mockit.*;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+
+import static org.testng.Assert.assertEquals;
+
+
+public class ModelProcessorTest {
+
+ @Injectable
+ ResolverCache cache;
+
+ @Injectable
+ Swagger swagger;
+
+ @Mocked
+ PropertyProcessor propertyProcessor;
+
+ @Mocked
+ ExternalRefProcessor externalRefProcessor;
+
+ @Test
+ public void testProcessRefModel_ExternalRef() throws Exception {
+
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final String newRef = "bar";
+
+ setupPropertyAndExternalRefProcessors();
+
+ new StrictExpectations() {{
+ externalRefProcessor.processRefToExternalDefinition(ref, RefFormat.URL);
+ times = 1;
+ result = newRef;
+ }};
+
+ RefModel refModel = new RefModel(ref);
+
+ new ModelProcessor(cache, swagger).processModel(refModel);
+
+ assertEquals(refModel.get$ref(), "#/definitions/bar");
+ }
+
+ @Test
+ public void testProcessRefModel_InternalRef() throws Exception {
+ final String ref = "#/definitions/bar";
+
+ setupPropertyAndExternalRefProcessors();
+
+ RefModel refModel = new RefModel(ref);
+
+ new ModelProcessor(cache, swagger).processModel(refModel);
+
+ assertEquals(refModel.get$ref(), ref);
+ }
+
+ @Test
+ public void testProcessArrayModel(@Injectable final Property property) throws Exception {
+ setupPropertyAndExternalRefProcessors();
+
+ new StrictExpectations() {{
+ propertyProcessor.processProperty(property);
+ times = 1;
+ }};
+
+ ArrayModel model = new ArrayModel();
+ model.setItems(property);
+
+ new ModelProcessor(cache, swagger).processModel(model);
+ }
+
+ @Test
+ public void testProcessComposedModel() throws Exception {
+ setupPropertyAndExternalRefProcessors();
+
+ final String ref1 = "http://my.company.com/path/to/file.json#/foo/bar";
+ final String ref2 = "http://my.company.com/path/to/file.json#/this/that";
+ final String ref3 = "http://my.company.com/path/to/file.json#/hello/world";
+
+ ModelProcessor modelProcessor = new ModelProcessor(cache, swagger);
+
+ new Expectations() {{
+ externalRefProcessor.processRefToExternalDefinition(ref1, RefFormat.URL);
+ times = 1;
+ result = "bar";
+ externalRefProcessor.processRefToExternalDefinition(ref2, RefFormat.URL);
+ times = 1;
+ result = "that";
+ externalRefProcessor.processRefToExternalDefinition(ref3, RefFormat.URL);
+ times = 1;
+ result = "world";
+ }};
+
+ ComposedModel composedModel = new ComposedModel();
+ composedModel.child(new RefModel(ref1));
+ composedModel.parent(new RefModel(ref2));
+ composedModel.interfaces(Arrays.asList(new RefModel(ref3)));
+
+ modelProcessor.processModel(composedModel);
+
+ new FullVerifications() {{
+ externalRefProcessor.processRefToExternalDefinition(ref1, RefFormat.URL);
+ times = 1;
+ externalRefProcessor.processRefToExternalDefinition(ref2, RefFormat.URL);
+ times = 1;
+ externalRefProcessor.processRefToExternalDefinition(ref3, RefFormat.URL);
+ times = 1;
+ }};
+
+ assertEquals(((RefModel) composedModel.getChild()).get$ref(), "#/definitions/bar");
+ assertEquals(((RefModel) composedModel.getParent()).get$ref(), "#/definitions/that");
+ assertEquals((composedModel.getInterfaces().get(0)).get$ref(), "#/definitions/world");
+ }
+
+ @Test
+ public void testProcessModelImpl(@Injectable final Property property1,
+ @Injectable final Property property2) throws Exception {
+ setupPropertyAndExternalRefProcessors();
+
+ ModelImpl model = new ModelImpl();
+ model.addProperty("foo", property1);
+ model.addProperty("bar", property2);
+
+ new Expectations() {{
+ propertyProcessor.processProperty(property1);
+ times = 1;
+ propertyProcessor.processProperty(property2);
+ times = 1;
+ }};
+
+ new ModelProcessor(cache, swagger).processModel(model);
+
+ new FullVerifications(){{}};
+ }
+
+ private void setupPropertyAndExternalRefProcessors() {
+ new StrictExpectations() {{
+ new PropertyProcessor(cache, swagger);
+ times = 1;
+ result = propertyProcessor;
+
+ new ExternalRefProcessor(cache, swagger);
+ times = 1;
+ result = externalRefProcessor;
+ }};
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/OperationProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/OperationProcessorTest.java
new file mode 100644
index 0000000000..b1d8abe0c5
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/OperationProcessorTest.java
@@ -0,0 +1,79 @@
+package io.swagger.parser.processors;
+
+
+import io.swagger.models.Operation;
+import io.swagger.models.RefResponse;
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+import mockit.Expectations;
+import mockit.FullVerifications;
+import mockit.Injectable;
+import mockit.Mocked;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+
+public class OperationProcessorTest {
+
+ @Injectable
+ ResolverCache cache;
+
+ @Injectable
+ Swagger swagger;
+
+ @Mocked
+ ParameterProcessor parameterProcessor;
+
+ @Mocked
+ ResponseProcessor responseProcessor;
+
+ @Test
+ public void testProcessOperation(@Injectable final List inputParameterList,
+ @Injectable final List outputParameterList,
+ @Injectable final Response incomingResponse,
+ @Injectable final Response resolvedResponse) throws Exception {
+
+ Operation operation = new Operation();
+ operation.setParameters(inputParameterList);
+
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ RefResponse refResponse = new RefResponse(ref);
+
+ operation.response(200, refResponse);
+ operation.response(400, incomingResponse);
+
+ new Expectations() {{
+ new ParameterProcessor(cache, swagger);
+ times = 1;
+ result = parameterProcessor;
+ new ResponseProcessor(cache, swagger);
+ times = 1;
+ result = responseProcessor;
+
+ parameterProcessor.processParameters(inputParameterList);
+ times = 1;
+ result = outputParameterList;
+
+ cache.loadRef(ref, RefFormat.URL, Response.class);
+ times = 1;
+ result = resolvedResponse;
+
+ responseProcessor.processResponse(incomingResponse);
+ times = 1;
+ responseProcessor.processResponse(resolvedResponse);
+ times = 1;
+ }};
+
+ new OperationProcessor(cache, swagger).processOperation(operation);
+
+ new FullVerifications() {{}};
+
+ assertEquals(operation.getResponses().get("200"), resolvedResponse);
+ assertEquals(operation.getParameters(), outputParameterList);
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ParameterProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ParameterProcessorTest.java
new file mode 100644
index 0000000000..201a21e7a7
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ParameterProcessorTest.java
@@ -0,0 +1,137 @@
+package io.swagger.parser.processors;
+
+import io.swagger.models.Model;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.*;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+import mockit.FullVerifications;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.testng.annotations.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+
+
+public class ParameterProcessorTest {
+
+
+ @Injectable
+ ResolverCache cache;
+
+ @Injectable
+ Swagger swagger;
+
+ @Mocked
+ ModelProcessor modelProcessor;
+
+ @Test
+ public void testProcessParameters_TypesThatAreNotRefOrBody(@Injectable final HeaderParameter headerParameter,
+ @Injectable final QueryParameter queryParameter,
+ @Injectable final CookieParameter cookieParameter,
+ @Injectable final PathParameter pathParameter,
+ @Injectable final FormParameter formParameter) throws Exception {
+ expectedModelProcessorCreation();
+
+ final List processedParameters = new ParameterProcessor(cache, swagger)
+ .processParameters(Arrays.asList(headerParameter,
+ queryParameter,
+ cookieParameter,
+ pathParameter,
+ formParameter));
+
+ new FullVerifications() {{
+ }};
+
+ assertEquals(processedParameters.size(), 5);
+ assertEquals(processedParameters.get(0), headerParameter);
+ assertEquals(processedParameters.get(1), queryParameter);
+ assertEquals(processedParameters.get(2), cookieParameter);
+ assertEquals(processedParameters.get(3), pathParameter);
+ assertEquals(processedParameters.get(4), formParameter);
+ }
+
+ @Test
+ public void testProcessParameters_RefToHeader(
+ @Injectable final HeaderParameter resolvedHeaderParam) throws Exception {
+ expectedModelProcessorCreation();
+
+ final String ref = "#/parameters/foo";
+ RefParameter refParameter = new RefParameter(ref);
+
+ expectLoadingRefFromCache(ref, RefFormat.INTERNAL, resolvedHeaderParam);
+
+ final List processedParameters = new ParameterProcessor(cache, swagger)
+ .processParameters(Arrays.asList(refParameter));
+
+ new FullVerifications(){{}};
+
+ assertEquals(processedParameters.size(), 1);
+ assertEquals(processedParameters.get(0), resolvedHeaderParam);
+ }
+
+ private void expectLoadingRefFromCache(final String ref, final RefFormat refFormat,
+ final Parameter resolvedParam) {
+ new StrictExpectations() {{
+ cache.loadRef(ref, refFormat, Parameter.class);
+ times = 1;
+ result = resolvedParam;
+ }};
+ }
+
+ @Test
+ public void testProcessParameters_BodyParameter(@Injectable final Model bodyParamSchema) throws Exception {
+
+ expectedModelProcessorCreation();
+
+ BodyParameter bodyParameter = new BodyParameter().schema(bodyParamSchema);
+
+ expectModelProcessorInvoked(bodyParamSchema);
+
+ final List processedParameters = new ParameterProcessor(cache, swagger)
+ .processParameters(Arrays.asList(bodyParameter));
+
+ new FullVerifications(){{}};
+
+ assertEquals(processedParameters.size(), 1);
+ assertEquals(processedParameters.get(0), bodyParameter);
+ }
+
+ private void expectModelProcessorInvoked(@Injectable final Model bodyParamSchema) {
+ new StrictExpectations(){{
+ modelProcessor.processModel(bodyParamSchema); times=1;
+ }};
+ }
+
+ @Test
+ public void testProcessParameters_RefToBodyParam(@Injectable final Model bodyParamSchema) throws Exception {
+ expectedModelProcessorCreation();
+
+ final String ref = "#/parameters/foo";
+ RefParameter refParameter = new RefParameter(ref);
+ final BodyParameter resolvedBodyParam = new BodyParameter().schema(bodyParamSchema);
+
+ expectLoadingRefFromCache(ref, RefFormat.INTERNAL, resolvedBodyParam);
+ expectModelProcessorInvoked(bodyParamSchema);
+
+ final List processedParameters = new ParameterProcessor(cache, swagger)
+ .processParameters(Arrays.asList(refParameter));
+
+ new FullVerifications(){{}};
+
+ assertEquals(processedParameters.size(), 1);
+ assertEquals(processedParameters.get(0), resolvedBodyParam);
+ }
+
+ private void expectedModelProcessorCreation() {
+ new StrictExpectations() {{
+ new ModelProcessor(cache, swagger);
+ times = 1;
+ result = modelProcessor;
+ }};
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/PathsProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/PathsProcessorTest.java
new file mode 100644
index 0000000000..2ad0da2a87
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/PathsProcessorTest.java
@@ -0,0 +1,86 @@
+package io.swagger.parser.processors;
+
+
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.RefPath;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+import mockit.Expectations;
+import mockit.FullVerifications;
+import mockit.Injectable;
+import mockit.Mocked;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+
+public class PathsProcessorTest {
+
+ @Injectable
+ ResolverCache cache;
+
+ @Mocked
+ ParameterProcessor parameterProcessor;
+
+ @Mocked
+ OperationProcessor operationProcessor;
+
+ @Test
+ public void testProcessPaths(@Injectable final List nonRefPathParameters,
+ @Injectable final List processedNonRefPathParameters,
+ @Injectable final List resolvedPathParamters,
+ @Injectable final List processedResolvedPathParameters,
+ @Injectable final Operation nonRefPathOperation,
+ @Injectable final Operation resolvedPathOperation) throws Exception {
+
+ final Swagger swagger = new Swagger();
+
+ final String ref = "http://my.company.com/path/to/file.json#/foo";
+ swagger.path("/foo", new RefPath(ref));
+
+ final Path nonRefPath = new Path();
+ swagger.path("/bar", nonRefPath);
+ nonRefPath.setParameters(nonRefPathParameters);
+ nonRefPath.get(nonRefPathOperation);
+
+ final Path resolvedPath = new Path();
+ resolvedPath.setParameters(resolvedPathParamters);
+ resolvedPath.get(resolvedPathOperation);
+
+ new Expectations() {{
+ new ParameterProcessor(cache, swagger);
+ times = 1;
+ result = parameterProcessor;
+ new OperationProcessor(cache, swagger);
+ times = 1;
+ result = operationProcessor;
+
+ cache.loadRef(ref, RefFormat.URL, Path.class);
+ times = 1;
+ result = resolvedPath;
+
+ parameterProcessor.processParameters(resolvedPathParamters);
+ times = 1;
+ result = processedResolvedPathParameters;
+
+ parameterProcessor.processParameters(nonRefPathParameters);
+ times=1;
+ result = processedNonRefPathParameters;
+
+ operationProcessor.processOperation(resolvedPathOperation);
+ operationProcessor.processOperation(nonRefPathOperation);
+ }};
+
+ new PathsProcessor(cache, swagger).processPaths();
+
+ new FullVerifications(){{}};
+
+ assertEquals(nonRefPath.getParameters(), processedNonRefPathParameters);
+ assertEquals(swagger.getPath("/foo"), resolvedPath);
+ assertEquals(resolvedPath.getParameters(), processedResolvedPathParameters);
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/PropertyProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/PropertyProcessorTest.java
new file mode 100644
index 0000000000..09c1ff1a59
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/PropertyProcessorTest.java
@@ -0,0 +1,114 @@
+package io.swagger.parser.processors;
+
+
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.ArrayProperty;
+import io.swagger.models.properties.MapProperty;
+import io.swagger.models.properties.RefProperty;
+import io.swagger.models.refs.RefFormat;
+import io.swagger.parser.ResolverCache;
+import mockit.FullVerifications;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+
+public class PropertyProcessorTest {
+
+ @Injectable
+ ResolverCache cache;
+
+ @Injectable
+ Swagger swagger;
+
+ @Mocked
+ ExternalRefProcessor externalRefProcessor;
+
+ @Test
+ public void testProcessRefProperty_ExternalRef() throws Exception {
+ expectCreationOfExternalRefProcessor();
+
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefProperty refProperty = new RefProperty(ref);
+
+ expectCallToExternalRefProcessor(ref, RefFormat.URL, "bar");
+
+ new PropertyProcessor(cache, swagger).processProperty(refProperty);
+
+ new FullVerifications() {{
+ }};
+
+ assertEquals(refProperty.get$ref(), "#/definitions/bar");
+ }
+
+ private void expectCallToExternalRefProcessor(final String ref, final RefFormat refFormat, final String newRef) {
+ new StrictExpectations() {{
+ externalRefProcessor.processRefToExternalDefinition(ref, refFormat);
+ times = 1;
+ result = newRef;
+ }};
+ }
+
+ @Test
+ public void testProcessRefProperty_InternalRef() throws Exception {
+ expectCreationOfExternalRefProcessor();
+
+ final String expectedRef = "#/definitions/foo";
+ final RefProperty property = new RefProperty(expectedRef);
+ new PropertyProcessor(cache, swagger).processProperty(property);
+
+ new FullVerifications() {{
+ }};
+
+ assertEquals(property.get$ref(), expectedRef);
+ }
+
+ @Test
+ public void testProcessArrayProperty_ItemsIsRefProperty() throws Exception {
+ expectCreationOfExternalRefProcessor();
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefProperty refProperty = new RefProperty(ref);
+
+ ArrayProperty arrayProperty = new ArrayProperty();
+ arrayProperty.setItems(refProperty);
+
+ expectCallToExternalRefProcessor(ref, RefFormat.URL, "bar");
+
+ new PropertyProcessor(cache, swagger).processProperty(arrayProperty);
+
+ new FullVerifications() {{
+ }};
+
+ assertEquals(((RefProperty)arrayProperty.getItems()).get$ref(), "#/definitions/bar");
+
+ }
+
+ @Test
+ public void testProcessMapProperty_AdditionalPropertiesIsRefProperty() throws Exception {
+ expectCreationOfExternalRefProcessor();
+ final String ref = "http://my.company.com/path/to/file.json#/foo/bar";
+ final RefProperty refProperty = new RefProperty(ref);
+
+ MapProperty mapProperty = new MapProperty();
+ mapProperty.setAdditionalProperties(refProperty);
+
+ expectCallToExternalRefProcessor(ref, RefFormat.URL, "bar");
+
+ new PropertyProcessor(cache, swagger).processProperty(mapProperty);
+
+ new FullVerifications() {{
+ }};
+
+ assertEquals(((RefProperty)mapProperty.getAdditionalProperties()).get$ref(), "#/definitions/bar");
+ }
+
+ private void expectCreationOfExternalRefProcessor() {
+ new StrictExpectations() {{
+ new ExternalRefProcessor(cache, swagger);
+ times = 1;
+ result = externalRefProcessor;
+ }};
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ResponseProcessorTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ResponseProcessorTest.java
new file mode 100644
index 0000000000..e201c72e1e
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/processors/ResponseProcessorTest.java
@@ -0,0 +1,44 @@
+package io.swagger.parser.processors;
+
+
+import io.swagger.models.Response;
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import io.swagger.models.properties.Property;
+import io.swagger.parser.ResolverCache;
+import mockit.FullVerifications;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.testng.annotations.Test;
+
+public class ResponseProcessorTest {
+
+ @Injectable
+ ResolverCache cache;
+
+ @Injectable
+ Swagger swagger;
+
+ @Mocked
+ PropertyProcessor propertyProcessor;
+
+ @Test
+ public void testProcessResponse(@Injectable final Property responseSchema,
+ @Injectable final Property responseHeader) throws Exception {
+
+ new StrictExpectations(){{
+ new PropertyProcessor(cache, swagger); times=1; result = propertyProcessor;
+
+ propertyProcessor.processProperty(responseSchema); times=1;
+ }};
+
+ Response response = new Response();
+ response.setSchema(responseSchema);
+ response.addHeader("foo", responseHeader);
+
+ new ResponseProcessor(cache, swagger).processResponse(response);
+
+ new FullVerifications(){{}};
+ }
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/util/DeserializationUtilsTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/util/DeserializationUtilsTest.java
new file mode 100644
index 0000000000..ed5f20a4f7
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/util/DeserializationUtilsTest.java
@@ -0,0 +1,157 @@
+package io.swagger.parser.util;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.swagger.models.Model;
+import io.swagger.util.Json;
+import io.swagger.util.Yaml;
+import mockit.Expectations;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+
+/**
+ * Created by russellb337 on 7/14/15.
+ */
+public class DeserializationUtilsTest {
+
+
+ @Test
+ public void testDeserializeYamlIntoObject(@Mocked Yaml yaml,
+ @Injectable final ObjectMapper objectMapper,
+ @Injectable final Model model) throws Exception {
+
+ String jsonStr = "really good yaml";
+
+
+ new Expectations() {{
+ Yaml.mapper();
+ result = objectMapper;
+ times = 1;
+ objectMapper.readValue(anyString, withAny(Object.class));
+ times = 1;
+ result = model;
+ }};
+
+ final Model result = DeserializationUtils.deserialize(jsonStr, "foo.yaml", Model.class);
+ assertEquals(model, result);
+ }
+
+ @Test
+ public void testDeserializeJsonIntoObject(@Mocked Json json,
+ @Injectable final ObjectMapper objectMapper,
+ @Injectable final Model model) throws Exception {
+
+ String jsonStr = "really good json";
+
+
+ new Expectations() {{
+ Json.mapper();
+ result = objectMapper;
+ times = 2;
+ objectMapper.readValue(anyString, withAny(Object.class));
+ times = 2;
+ result = model;
+ }};
+
+ Model result = DeserializationUtils.deserialize(jsonStr, "foo.json", Model.class);
+ assertEquals(model, result);
+
+ result = DeserializationUtils.deserialize(jsonStr, "foo", Model.class);
+ assertEquals(model, result);
+ }
+
+ @Test
+ public void testDeserializeJsonTreeIntoObject(@Mocked Json json,
+ @Injectable final ObjectMapper objectMapper,
+ @Injectable final Model model,
+ @Injectable final JsonNode node) throws Exception {
+
+ new Expectations() {{
+ Json.mapper();
+ result = objectMapper;
+ times = 2;
+ objectMapper.convertValue(node, Model.class);
+ times = 2;
+ result = model;
+ }};
+
+ Model result = DeserializationUtils.deserialize(node, "foo.json", Model.class);
+ assertEquals(model, result);
+
+ result = DeserializationUtils.deserialize(node, "foo", Model.class);
+ assertEquals(model, result);
+
+
+ }
+
+ @Test
+ public void testDeserializeYamlTreeIntoObject(@Mocked Yaml yaml,
+ @Injectable final ObjectMapper objectMapper,
+ @Injectable final Model model,
+ @Injectable final JsonNode node) throws Exception {
+
+ new StrictExpectations() {{
+ Yaml.mapper();
+ result = objectMapper;
+ times = 1;
+ objectMapper.convertValue(node, Model.class);
+ times = 1;
+ result = model;
+ }};
+
+ Model result = DeserializationUtils.deserialize(node, "foo.yaml", Model.class);
+ assertEquals(model, result);
+ }
+
+ @Test
+ public void testDeserializeYamlIntoTree(@Mocked Yaml yaml,
+ @Injectable final ObjectMapper objectMapper,
+ @Injectable final JsonNode jsonNode) throws Exception {
+
+ String jsonStr = "really good yaml";
+
+ new Expectations() {{
+ Yaml.mapper();
+ result = objectMapper;
+ times = 1;
+ objectMapper.readTree(anyString);
+ result = jsonNode;
+ times = 1;
+ }};
+
+ final JsonNode result = DeserializationUtils.deserializeIntoTree(jsonStr, "foo.yaml");
+ assertEquals(jsonNode, result);
+ }
+
+ @Test
+ public void testDeserializeJsonIntoTree(@Mocked Json json,
+ @Injectable final ObjectMapper objectMapper,
+ @Injectable final JsonNode jsonNode) throws Exception {
+
+ String jsonStr = "really good json";
+
+ new Expectations() {{
+ Json.mapper();
+ result = objectMapper;
+ times = 2;
+ objectMapper.readTree(anyString);
+ result = jsonNode;
+ times = 2;
+ }};
+
+ JsonNode result = DeserializationUtils.deserializeIntoTree(jsonStr, "foo.json");
+ assertTrue(jsonNode == result);
+
+ result = DeserializationUtils.deserializeIntoTree(jsonStr, "foo");
+ assertTrue(jsonNode == result);
+ }
+
+
+}
diff --git a/modules/swagger-parser/src/test/java/io/swagger/parser/util/RefUtilsTest.java b/modules/swagger-parser/src/test/java/io/swagger/parser/util/RefUtilsTest.java
new file mode 100644
index 0000000000..c9f00bfeec
--- /dev/null
+++ b/modules/swagger-parser/src/test/java/io/swagger/parser/util/RefUtilsTest.java
@@ -0,0 +1,214 @@
+package io.swagger.parser.util;
+
+import io.swagger.models.Model;
+import io.swagger.models.ModelImpl;
+import io.swagger.models.auth.AuthorizationValue;
+import io.swagger.models.refs.RefFormat;
+import mockit.Injectable;
+import mockit.Mocked;
+import mockit.StrictExpectations;
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.testng.Assert.*;
+
+
+public class RefUtilsTest {
+
+ @Test
+ public void testComputeDefinitionName() throws Exception {
+ //URL refs
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.json", "file");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.json#/foo", "foo");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.json#/foo/bar", "bar");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.json#/foo/bar/hello", "hello");
+
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file", "file");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file#/foo", "foo");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file#/foo/bar", "bar");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file#/foo/bar/hello", "hello");
+
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.yaml", "file");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.yaml#/foo", "foo");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.yaml#/foo/bar", "bar");
+ doComputeDefinitionNameTestCase("http://my.company.com/path/to/file.yaml#/foo/bar/hello", "hello");
+
+ //Relative file refs
+ doComputeDefinitionNameTestCase("./path/to/file.json", "file");
+ doComputeDefinitionNameTestCase("./path/to/file.json#/foo", "foo");
+ doComputeDefinitionNameTestCase("./path/to/file.json#/foo/bar", "bar");
+ doComputeDefinitionNameTestCase("./path/to/file.json#/foo/bar/hello", "hello");
+
+ doComputeDefinitionNameTestCase("./path/to/file.yaml", "file");
+ doComputeDefinitionNameTestCase("./path/to/file.yaml#/foo", "foo");
+ doComputeDefinitionNameTestCase("./path/to/file.yaml#/foo/bar", "bar");
+ doComputeDefinitionNameTestCase("./path/to/file.yaml#/foo/bar/hello", "hello");
+
+ doComputeDefinitionNameTestCase("./path/to/file", "file");
+ doComputeDefinitionNameTestCase("./path/to/file#/foo", "foo");
+ doComputeDefinitionNameTestCase("./path/to/file#/foo/bar", "bar");
+ doComputeDefinitionNameTestCase("./path/to/file#/foo/bar/hello", "hello");
+
+
+ }
+
+ private void doComputeDefinitionNameTestCase(String ref, String expectedDefinitionName) {
+ assertEquals(expectedDefinitionName, RefUtils.computeDefinitionName(ref));
+ }
+
+ @Test
+ public void testDeconflictName() throws Exception {
+ doDeconflictNameTestCase("foo", "foo");
+ doDeconflictNameTestCase("foo", "foo1", "foo");
+ doDeconflictNameTestCase("foo", "foo2", "foo", "foo1");
+ doDeconflictNameTestCase("foo", "foo3", "foo", "foo1", "foo2");
+ }
+
+ private void doDeconflictNameTestCase(String input, String expectedOutput, String... existingKeys) {
+ assertEquals(expectedOutput, RefUtils.deconflictName(input, createMap(existingKeys)));
+ }
+
+ private Map createMap(String... keys) {
+ Map definitionMap = new HashMap<>();
+
+ for (String key : keys) {
+ definitionMap.put(key, new ModelImpl());
+ }
+
+ return definitionMap;
+ }
+
+ @Test
+ public void testIsAnExternalRefFormat() throws Exception {
+ final RefFormat[] values = RefFormat.values();
+
+ for (RefFormat value : values) {
+ switch (value) {
+
+ case URL:
+ case RELATIVE:
+ assertTrue(RefUtils.isAnExternalRefFormat(value));
+ break;
+ case INTERNAL:
+ assertFalse(RefUtils.isAnExternalRefFormat(value));
+ break;
+ default:
+ fail("Unhandled RefFormat condition: " + value);
+ }
+ }
+ }
+
+ @Test
+ public void testReadExternalRef_UrlFormat(@Injectable final List auths,
+ @Mocked RemoteUrl remoteUrl
+ ) throws Exception {
+
+ final String url = "http://my.company.com/path/to/file.json";
+ final String expectedResult = "really good json";
+
+ new StrictExpectations() {{
+ RemoteUrl.urlToString(url, auths);
+ times = 1;
+ result = expectedResult;
+ }};
+
+ String actualResult = RefUtils.readExternalRef(url, RefFormat.URL, auths, null);
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ public void testReadExternalRef_UrlFormat_ExceptionThrown(@Injectable final List auths,
+ @Injectable final Exception mockedException,
+ @Mocked RemoteUrl remoteUrl
+ ) throws Exception {
+
+ final String url = "http://my.company.com/path/to/file.json";
+
+ new StrictExpectations() {{
+ RemoteUrl.urlToString(url, auths);
+ times = 1;
+ result = mockedException;
+ }};
+
+ try {
+ RefUtils.readExternalRef(url, RefFormat.URL, auths, null);
+ fail("Should have thrown an exception");
+ } catch (RuntimeException e) {
+ assertEquals(mockedException, e.getCause());
+ }
+
+ }
+
+ @Test
+ public void testReadExternalRef_RelativeFileFormat(@Injectable final List auths,
+ @Mocked IOUtils ioUtils,
+ @Mocked final FileInputStream fileInputStream
+ ) throws Exception {
+
+ final Path parentDirectory = Paths.get("src/test/resources");
+ final String file = "./path/to/file.json";
+ final String expectedResult = "really good json";
+
+ new StrictExpectations() {{
+ new FileInputStream("src/test/resources/path/to/file.json");
+ times = 1;
+ result = fileInputStream;
+
+ IOUtils.toString(fileInputStream);
+ times = 1;
+ result = expectedResult;
+ }};
+
+ String actualResult = RefUtils.readExternalRef(file, RefFormat.RELATIVE, auths, parentDirectory);
+ assertEquals(expectedResult, actualResult);
+ }
+
+ @Test
+ public void testReadExternalRef_RelativeFileFormat_ExceptionThrown(@Injectable final List auths,
+ @Mocked IOUtils ioUtils,
+ @Mocked final FileInputStream fileInputStream,
+ @Injectable final IOException mockedException
+ ) throws Exception {
+ final String file = "./path/to/file.json";
+ final Path parentDirectory = Paths.get("src/test/resources");
+
+ new StrictExpectations() {{
+ new FileInputStream("src/test/resources/path/to/file.json");
+ times = 1;
+ result = fileInputStream;
+
+ IOUtils.toString(fileInputStream);
+ times = 1;
+ result = mockedException;
+ }};
+
+ try {
+ RefUtils.readExternalRef(file, RefFormat.RELATIVE, auths, parentDirectory);
+ fail("Should have thrown an exception");
+ } catch(RuntimeException e) {
+ assertEquals(mockedException, e.getCause());
+ }
+ }
+
+ @Test
+ public void testReadExternalRef_InternalFormat(@Injectable final List auths) throws Exception {
+
+ final String file = "#/defintiions/foo";
+
+ try {
+ RefUtils.readExternalRef(file, RefFormat.INTERNAL, auths, null);
+ fail("Should have thrown an exception");
+ } catch(RuntimeException e) {
+
+ }
+ }
+
+}
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/conflict.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/conflict.json
new file mode 100644
index 0000000000..771ec3bcdd
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/conflict.json
@@ -0,0 +1,14 @@
+{
+ "foo": {
+ "description": "A model that will generate an intentional name conflict with foo.json",
+ "type": "object",
+ "properties": {
+ "hello1": {
+ "type": "string"
+ },
+ "world2": {
+ "type": "integer"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/error.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/error.json
new file mode 100644
index 0000000000..c7956267da
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/error.json
@@ -0,0 +1,12 @@
+{
+ "description": "The error model",
+ "type": "object",
+ "properties": {
+ "code": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/example.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/example.json
new file mode 100644
index 0000000000..92bbf6e52b
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/example.json
@@ -0,0 +1,12 @@
+{
+ "description": "The example model",
+ "type": "object",
+ "properties": {
+ "foo": {
+ "type": "string"
+ },
+ "bar": {
+ "type": "integer"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/foo.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/foo.json
new file mode 100644
index 0000000000..22ca1c2443
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/foo.json
@@ -0,0 +1,12 @@
+{
+ "description": "Just another model",
+ "type": "object",
+ "properties": {
+ "hello": {
+ "type": "string"
+ },
+ "world": {
+ "type": "integer"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/health.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/health.json
new file mode 100644
index 0000000000..064fabb61d
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/health.json
@@ -0,0 +1,12 @@
+{
+ "description": "The health model",
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "cpuUtilization": {
+ "type": "integer"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/pet.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/pet.json
new file mode 100644
index 0000000000..1c80d03056
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/pet.json
@@ -0,0 +1,15 @@
+{
+ "discriminator": "petType",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "petType": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name",
+ "petType"
+ ]
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/models/reflex.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/reflex.json
new file mode 100644
index 0000000000..a40a11fdfd
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/models/reflex.json
@@ -0,0 +1,11 @@
+{
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "speedInMilliseconds": {
+ "type": "integer"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/parameters/params.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/parameters/params.json
new file mode 100644
index 0000000000..c4a1d82bb3
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/parameters/params.json
@@ -0,0 +1,26 @@
+{
+ "param1" : {
+ "name": "param1",
+ "in": "query",
+ "required": false,
+ "type": "string"
+ },
+ "param2": {
+ "name": "param2",
+ "in": "header",
+ "required": false,
+ "type": "string"
+ },
+ "param3": {
+ "name": "param3",
+ "in": "path",
+ "required": false,
+ "type": "string"
+ },
+ "param4": {
+ "name": "param4",
+ "in": "header",
+ "required": false,
+ "type": "string"
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/parent.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/parent.json
new file mode 100644
index 0000000000..5ad953a68b
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/parent.json
@@ -0,0 +1,64 @@
+{
+ "swagger": "2.0",
+ "paths": {
+ "/health": {
+ "$ref": "./paths/healthPath.json"
+ }
+ },
+ "definitions": {
+ "refInDefinitions" : {
+ "$ref": "./models/example.json"
+ },
+ "arrayModel" : {
+ "type": "array",
+ "items": {
+ "$ref": "./models/foo.json"
+ }
+ },
+ "composedCat": {
+ "allOf": [
+ {
+ "$ref": "./models/pet.json"
+ },
+ {
+ "$ref": "./models/conflict.json#/foo"
+ },
+ {
+ "properties": {
+ "huntingSkill": {
+ "type": "string",
+ "description": "The measured skill for hunting",
+ "default": "lazy",
+ "enum": [
+ "clueless",
+ "lazy",
+ "adventurous",
+ "aggressive"
+ ]
+ },
+ "prop2": {
+ "$ref": "./models/foo.json"
+ },
+ "reflexes": {
+ "type": "array",
+ "items": {
+ "$ref": "./models/reflex.json"
+ }
+ },
+ "reflexMap": {
+ "type": "object",
+ "additionalProperties": {
+ "$ref": "./models/reflex.json"
+ }
+ }
+
+ },
+ "required": [
+ "huntingSkill"
+ ]
+ }
+ ]
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/paths/healthPath.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/paths/healthPath.json
new file mode 100644
index 0000000000..15395b4edf
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/paths/healthPath.json
@@ -0,0 +1,47 @@
+{
+ "parameters": [
+ {
+ "$ref": "./parameters/params.json#/param1"
+ },
+ {
+ "$ref": "./parameters/params.json#/param2"
+ }
+ ],
+ "get": {
+ "summary": "Returns server health information",
+ "operationId": "getHealth",
+ "produces": [
+ "application/json"
+ ],
+ "parameters": [
+ {
+ "$ref": "./parameters/params.json#/param3"
+ },
+ {
+ "$ref": "./parameters/params.json#/param4"
+ },
+ {
+ "name": "body",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "$ref": "./models/health.json"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Health information from the server",
+ "schema": {
+ "$ref": "./models/health.json"
+ }
+ },
+ "400": {
+ "$ref": "./responses/errorResponses.json#/bad-request"
+ },
+ "500": {
+ "$ref": "./responses/errorResponses.json#/internal-server-error"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/resources/relative-file-references/json/responses/errorResponses.json b/modules/swagger-parser/src/test/resources/relative-file-references/json/responses/errorResponses.json
new file mode 100644
index 0000000000..ce17bf193f
--- /dev/null
+++ b/modules/swagger-parser/src/test/resources/relative-file-references/json/responses/errorResponses.json
@@ -0,0 +1,14 @@
+{
+ "bad-request": {
+ "description": "Your request was not valid",
+ "schema": {
+ "$ref": "./models/error.json"
+ }
+ },
+ "internal-server-error": {
+ "description": "An unexpected error occur during processing",
+ "schema": {
+ "$ref": "./models/error.json"
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/swagger-parser/src/test/scala/SwaggerResolverTest.scala b/modules/swagger-parser/src/test/scala/SwaggerResolverTest.scala
index 00bea7ccd0..ed391bac9d 100644
--- a/modules/swagger-parser/src/test/scala/SwaggerResolverTest.scala
+++ b/modules/swagger-parser/src/test/scala/SwaggerResolverTest.scala
@@ -14,7 +14,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
"Sample", new ModelImpl()
.property("remoteRef", new RefProperty("http://petstore.swagger.io/v2/swagger.json#/definitions/Tag")))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val prop = resolved.getDefinitions().get("Sample").getProperties().get("remoteRef")
prop.isInstanceOf[RefProperty] should be(true)
val ref = prop.asInstanceOf[RefProperty]
@@ -28,7 +28,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
"Sample", new ModelImpl()
.property("remoteRef", new RefProperty("http://petstore.swagger.io/v2/swagger.yaml#/definitions/Tag")))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val prop = resolved.getDefinitions().get("Sample").getProperties().get("remoteRef")
prop.isInstanceOf[RefProperty] should be(true)
val ref = prop.asInstanceOf[RefProperty]
@@ -42,7 +42,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
"Sample", new ModelImpl()
.property("remoteRef", new ArrayProperty(new RefProperty("http://petstore.swagger.io/v2/swagger.json#/definitions/Tag"))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val prop = resolved.getDefinitions().get("Sample").getProperties().get("remoteRef")
prop.isInstanceOf[ArrayProperty] should be(true)
val ap = prop.asInstanceOf[ArrayProperty]
@@ -57,7 +57,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
"Sample", new ModelImpl()
.property("remoteRef", new ArrayProperty(new RefProperty("http://petstore.swagger.io/v2/swagger.yaml#/definitions/Tag"))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val prop = resolved.getDefinitions().get("Sample").getProperties().get("remoteRef")
prop.isInstanceOf[ArrayProperty] should be(true)
val ap = prop.asInstanceOf[ArrayProperty]
@@ -71,7 +71,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
swagger.addDefinition(
"Sample", new ModelImpl()
.property("remoteRef", new MapProperty(new RefProperty("http://petstore.swagger.io/v2/swagger.json#/definitions/Tag"))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val prop = resolved.getDefinitions().get("Sample").getProperties().get("remoteRef")
prop.isInstanceOf[MapProperty] should be(true)
val ap = prop.asInstanceOf[MapProperty]
@@ -85,7 +85,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
swagger.addDefinition(
"Sample", new ModelImpl()
.property("remoteRef", new MapProperty(new RefProperty("http://petstore.swagger.io/v2/swagger.yaml#/definitions/Tag"))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val prop = resolved.getDefinitions().get("Sample").getProperties().get("remoteRef")
prop.isInstanceOf[MapProperty] should be(true)
val ap = prop.asInstanceOf[MapProperty]
@@ -101,7 +101,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.parameter(new BodyParameter()
.schema(new RefModel("http://petstore.swagger.io/v2/swagger.json#/definitions/Tag")))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val param = swagger.getPaths().get("/fun").getGet().getParameters().get(0).asInstanceOf[BodyParameter]
val ref = param.getSchema().asInstanceOf[RefModel]
ref.get$ref() should equal("#/definitions/Tag")
@@ -115,7 +115,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.parameter(new BodyParameter()
.schema(new RefModel("http://petstore.swagger.io/v2/swagger.yaml#/definitions/Tag")))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val param = swagger.getPaths().get("/fun").getGet().getParameters().get(0).asInstanceOf[BodyParameter]
val ref = param.getSchema().asInstanceOf[RefModel]
ref.get$ref() should equal("#/definitions/Tag")
@@ -132,7 +132,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.name("skip")
.property(new IntegerProperty()))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val params = swagger.getPaths().get("/fun").getGet().getParameters()
params.size() should be(1)
val param = params.get(0).asInstanceOf[QueryParameter]
@@ -156,7 +156,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.schema(schema))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val params = swagger.getPaths().get("/fun").getGet().getParameters()
params.size() should be(1)
val param = params.get(0).asInstanceOf[BodyParameter]
@@ -169,7 +169,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.get(new Operation()
.response(200, new Response()
.schema(new RefProperty("http://petstore.swagger.io/v2/swagger.json#/definitions/Tag")))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val response = swagger.getPaths().get("/fun").getGet().getResponses().get("200")
val ref = response.getSchema.asInstanceOf[RefProperty]
ref.get$ref() should equal("#/definitions/Tag")
@@ -182,7 +182,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.get(new Operation()
.response(200, new Response()
.schema(new RefProperty("http://petstore.swagger.io/v2/swagger.yaml#/definitions/Tag")))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val response = swagger.getPaths().get("/fun").getGet().getResponses().get("200")
val ref = response.getSchema.asInstanceOf[RefProperty]
ref.get$ref() should equal("#/definitions/Tag")
@@ -197,7 +197,7 @@ class SwaggerResolverTest extends FlatSpec with Matchers {
.schema(
new ArrayProperty(
new RefProperty("http://petstore.swagger.io/v2/swagger.yaml#/definitions/Tag"))))))
- val resolved = new SwaggerResolver().resolve(swagger, null)
+ val resolved = new SwaggerResolver(swagger, null).resolve()
val response = swagger.getPaths().get("/fun").getGet().getResponses().get("200")
val array = response.getSchema.asInstanceOf[ArrayProperty]
array.getItems() should not be (null)
diff --git a/pom.xml b/pom.xml
index 68218c230d..09f3268ab0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -181,6 +181,18 @@
swagger-core
${swagger-core-version}
+
+ org.testng
+ testng
+ ${testng-version}
+ test
+
+
+ org.jmockit
+ jmockit
+ ${jmockit-version}
+ test
+
org.scala-lang
scala-library
@@ -209,8 +221,10 @@
2.4
2.10.4
1.6.3
- 1.5.1
+ 1.5.3-SNAPSHOT
4.8.1
+ 6.9.6
2.1.3
+ 1.18