diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java index bff78820b25..08a04769e87 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/examples/ExampleGenerator.java @@ -1,5 +1,8 @@ package io.swagger.codegen.examples; +import static io.swagger.models.properties.StringProperty.Format.URI; +import static io.swagger.models.properties.StringProperty.Format.URL; + import io.swagger.models.Model; import io.swagger.models.ModelImpl; import io.swagger.models.properties.ArrayProperty; @@ -11,7 +14,6 @@ import io.swagger.models.properties.DecimalProperty; import io.swagger.models.properties.DoubleProperty; import io.swagger.models.properties.FileProperty; import io.swagger.models.properties.FloatProperty; -import io.swagger.models.properties.IntegerProperty; import io.swagger.models.properties.LongProperty; import io.swagger.models.properties.MapProperty; import io.swagger.models.properties.ObjectProperty; @@ -20,10 +22,12 @@ import io.swagger.models.properties.RefProperty; import io.swagger.models.properties.StringProperty; import io.swagger.models.properties.UUIDProperty; import io.swagger.util.Json; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -31,6 +35,17 @@ import java.util.Map; import java.util.Set; public class ExampleGenerator { + private static final Logger logger = LoggerFactory.getLogger(ExampleGenerator.class); + + // TODO: move constants to more appropriate location + private static final String MIME_TYPE_JSON = "application/json"; + private static final String MIME_TYPE_XML = "application/xml"; + + private static final String EXAMPLE = "example"; + private static final String CONTENT_TYPE = "contentType"; + private static final String OUTPUT = "output"; + private static final String NONE = "none"; + protected Map examples; public ExampleGenerator(Map examples) { @@ -38,53 +53,76 @@ public class ExampleGenerator { } public List> generate(Map examples, List mediaTypes, Property property) { - List> output = new ArrayList>(); - Set processedModels = new HashSet(); + List> output = new ArrayList<>(); + Set processedModels = new HashSet<>(); if (examples == null) { if (mediaTypes == null) { // assume application/json for this - mediaTypes = Arrays.asList("application/json"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. + mediaTypes = Collections.singletonList(MIME_TYPE_JSON); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'. } for (String mediaType : mediaTypes) { - Map kv = new HashMap(); - kv.put("contentType", mediaType); - if (property != null && mediaType.startsWith("application/json")) { + Map kv = new HashMap<>(); + kv.put(CONTENT_TYPE, mediaType); + if (property != null && mediaType.startsWith(MIME_TYPE_JSON)) { String example = Json.pretty(resolvePropertyToExample(mediaType, property, processedModels)); if (example != null) { - kv.put("example", example); + kv.put(EXAMPLE, example); output.add(kv); } - } else if (property != null && mediaType.startsWith("application/xml")) { + } else if (property != null && mediaType.startsWith(MIME_TYPE_XML)) { String example = new XmlExampleGenerator(this.examples).toXml(property); if (example != null) { - kv.put("example", example); + kv.put(EXAMPLE, example); output.add(kv); } } } } else { for (Map.Entry entry : examples.entrySet()) { - final Map kv = new HashMap(); - kv.put("contentType", entry.getKey()); - kv.put("example", Json.pretty(entry.getValue())); + final Map kv = new HashMap<>(); + kv.put(CONTENT_TYPE, entry.getKey()); + kv.put(EXAMPLE, Json.pretty(entry.getValue())); output.add(kv); } } if (output.size() == 0) { - Map kv = new HashMap(); - kv.put("output", "none"); + Map kv = new HashMap<>(); + kv.put(OUTPUT, NONE); output.add(kv); } return output; } - protected Object resolvePropertyToExample(String mediaType, Property property, Set processedModels) { + private Object resolvePropertyToExample(String mediaType, Property property, Set processedModels) { + logger.debug("Resolving example for property {}...", property); if (property.getExample() != null) { + logger.debug("Example set in swagger spec, returning example: '{}'", property.getExample().toString()); return property.getExample(); } else if (property instanceof StringProperty) { + logger.debug("String property"); + String defaultValue = ((StringProperty) property).getDefault(); + if (defaultValue != null && !defaultValue.isEmpty()) { + logger.debug("Default value found: '{}'", defaultValue); + return defaultValue; + } + List enumValues = ((StringProperty) property).getEnum(); + if (enumValues != null && !enumValues.isEmpty()) { + logger.debug("Enum value found: '{}'", enumValues.get(0)); + return enumValues.get(0); + } + String format = property.getFormat(); + if (format != null && (URI.getName().equals(format) || URL.getName().equals(format))) { + logger.debug("URI or URL format, without default or enum, generating random one."); + return "http://example.com/aeiou"; + } + logger.debug("No values found, using default string 'aeiou' as example"); return "aeiou"; } else if (property instanceof BooleanProperty) { + Boolean defaultValue = ((BooleanProperty) property).getDefault(); + if (defaultValue != null) { + return defaultValue; + } return Boolean.TRUE; } else if (property instanceof ArrayProperty) { Property innerType = ((ArrayProperty) property).getItems(); @@ -97,21 +135,28 @@ public class ExampleGenerator { return "2000-01-23"; } else if (property instanceof DateTimeProperty) { return "2000-01-23T04:56:07.000+00:00"; - } else if (property instanceof DecimalProperty) { - return new BigDecimal(1.3579); } else if (property instanceof DoubleProperty) { - return 3.149; + Double min = ((DecimalProperty) property).getMinimum() == null ? null : ((DecimalProperty) property).getMinimum().doubleValue(); + Double max = ((DecimalProperty) property).getMaximum() == null ? null : ((DecimalProperty) property).getMaximum().doubleValue(); + return randomNumber(min, max); + } else if (property instanceof FloatProperty) { + Double min = ((DecimalProperty) property).getMinimum() == null ? null : ((DecimalProperty) property).getMinimum().doubleValue(); + Double max = ((DecimalProperty) property).getMaximum() == null ? null : ((DecimalProperty) property).getMaximum().doubleValue(); + return (float) randomNumber(min, max); + } else if (property instanceof DecimalProperty) { + Double min = ((DecimalProperty) property).getMinimum() == null ? null : ((DecimalProperty) property).getMinimum().doubleValue(); + Double max = ((DecimalProperty) property).getMaximum() == null ? null : ((DecimalProperty) property).getMaximum().doubleValue(); + return new BigDecimal(randomNumber(min, max)); } else if (property instanceof FileProperty) { return ""; // TODO - } else if (property instanceof FloatProperty) { - return 1.23f; - } else if (property instanceof IntegerProperty) { - return 123; } else if (property instanceof LongProperty) { - return 123456789L; - // Properties that are not Integer or Long may still be BaseInteger - } else if (property instanceof BaseIntegerProperty) { - return 123; + Double min = ((BaseIntegerProperty) property).getMinimum() == null ? null : ((BaseIntegerProperty) property).getMinimum().doubleValue(); + Double max = ((BaseIntegerProperty) property).getMaximum() == null ? null : ((BaseIntegerProperty) property).getMaximum().doubleValue(); + return (long) randomNumber(min, max); + } else if (property instanceof BaseIntegerProperty) { // Includes IntegerProperty + Double min = ((BaseIntegerProperty) property).getMinimum() == null ? null : ((BaseIntegerProperty) property).getMinimum().doubleValue(); + Double max = ((BaseIntegerProperty) property).getMaximum() == null ? null : ((BaseIntegerProperty) property).getMaximum().doubleValue(); + return (int) randomNumber(min, max); } else if (property instanceof MapProperty) { Map mp = new HashMap(); if (property.getName() != null) { @@ -126,10 +171,12 @@ public class ExampleGenerator { return "{}"; } else if (property instanceof RefProperty) { String simpleName = ((RefProperty) property).getSimpleRef(); + logger.debug("Ref property, simple name: {}", simpleName); Model model = examples.get(simpleName); if (model != null) { return resolveModelToExample(simpleName, mediaType, model, processedModels); } + logger.warn("Ref property with empty model."); } else if (property instanceof UUIDProperty) { return "046b6c7f-0b8a-43b9-b35d-6489e6daee91"; } @@ -137,16 +184,35 @@ public class ExampleGenerator { return ""; } - public Object resolveModelToExample(String name, String mediaType, Model model, Set processedModels) { + private double randomNumber(Double min, Double max) { + if (min != null && max != null) { + double range = max - min; + return Math.random() * range + min; + } else if (min != null) { + return Math.random() + min; + } else if (max != null) { + return Math.random() * max; + } else { + return Math.random() * 10; + } + } + + private Object resolveModelToExample(String name, String mediaType, Model model, Set processedModels) { if (processedModels.contains(name)) { return ""; } if (model instanceof ModelImpl) { processedModels.add(name); ModelImpl impl = (ModelImpl) model; - Map values = new HashMap(); + Map values = new HashMap<>(); - if (impl.getProperties() != null) { + logger.debug("Resolving model '{}' to example", name); + + if (impl.getExample() != null) { + logger.debug("Using example from spec: {}", impl.getExample()); + return impl.getExample(); + } else if (impl.getProperties() != null) { + logger.debug("Creating example from model values"); for (String propertyName : impl.getProperties().keySet()) { Property property = impl.getProperties().get(propertyName); values.put(propertyName, resolvePropertyToExample(mediaType, property, processedModels)); diff --git a/samples/server/petstore/nodejs/api/swagger.yaml b/samples/server/petstore/nodejs/api/swagger.yaml index 64049d2fdcc..3be49fdd5f2 100644 --- a/samples/server/petstore/nodejs/api/swagger.yaml +++ b/samples/server/petstore/nodejs/api/swagger.yaml @@ -586,10 +586,6 @@ paths: description: "User not found" x-swagger-router-controller: "User" securityDefinitions: - api_key: - type: "apiKey" - name: "api_key" - in: "header" petstore_auth: type: "oauth2" authorizationUrl: "http://petstore.swagger.io/api/oauth/dialog" @@ -597,6 +593,10 @@ securityDefinitions: scopes: write:pets: "modify pets in your account" read:pets: "read your pets" + api_key: + type: "apiKey" + name: "api_key" + in: "header" definitions: Order: type: "object" diff --git a/samples/server/petstore/nodejs/controllers/PetService.js b/samples/server/petstore/nodejs/controllers/PetService.js index 8a4235a35fc..b0a9f8edacc 100644 --- a/samples/server/petstore/nodejs/controllers/PetService.js +++ b/samples/server/petstore/nodejs/controllers/PetService.js @@ -33,18 +33,18 @@ exports.findPetsByStatus = function(args, res, next) { **/ var examples = {}; examples['application/json'] = [ { - "tags" : [ { - "id" : 123456789, - "name" : "aeiou" - } ], - "id" : 123456789, - "category" : { - "id" : 123456789, - "name" : "aeiou" - }, - "status" : "aeiou", + "photoUrls" : [ "aeiou" ], "name" : "doggie", - "photoUrls" : [ "aeiou" ] + "id" : 1, + "category" : { + "name" : "aeiou", + "id" : 7 + }, + "tags" : [ { + "name" : "aeiou", + "id" : 2 + } ], + "status" : "available" } ]; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); @@ -64,18 +64,18 @@ exports.findPetsByTags = function(args, res, next) { **/ var examples = {}; examples['application/json'] = [ { - "tags" : [ { - "id" : 123456789, - "name" : "aeiou" - } ], - "id" : 123456789, - "category" : { - "id" : 123456789, - "name" : "aeiou" - }, - "status" : "aeiou", + "photoUrls" : [ "aeiou" ], "name" : "doggie", - "photoUrls" : [ "aeiou" ] + "id" : 9, + "category" : { + "name" : "aeiou", + "id" : 7 + }, + "tags" : [ { + "name" : "aeiou", + "id" : 4 + } ], + "status" : "available" } ]; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); @@ -95,18 +95,18 @@ exports.getPetById = function(args, res, next) { **/ var examples = {}; examples['application/json'] = { - "tags" : [ { - "id" : 123456789, - "name" : "aeiou" - } ], - "id" : 123456789, - "category" : { - "id" : 123456789, - "name" : "aeiou" - }, - "status" : "aeiou", + "photoUrls" : [ "aeiou" ], "name" : "doggie", - "photoUrls" : [ "aeiou" ] + "id" : 4, + "category" : { + "name" : "aeiou", + "id" : 4 + }, + "tags" : [ { + "name" : "aeiou", + "id" : 4 + } ], + "status" : "available" }; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); @@ -152,9 +152,9 @@ exports.uploadFile = function(args, res, next) { **/ var examples = {}; examples['application/json'] = { - "message" : "aeiou", - "code" : 123, - "type" : "aeiou" + "code" : 7, + "type" : "aeiou", + "message" : "aeiou" }; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); diff --git a/samples/server/petstore/nodejs/controllers/StoreService.js b/samples/server/petstore/nodejs/controllers/StoreService.js index 7da8e0ceb23..ec122dc6368 100644 --- a/samples/server/petstore/nodejs/controllers/StoreService.js +++ b/samples/server/petstore/nodejs/controllers/StoreService.js @@ -20,7 +20,7 @@ exports.getInventory = function(args, res, next) { **/ var examples = {}; examples['application/json'] = { - "key" : 123 + "key" : 0 }; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); @@ -40,12 +40,12 @@ exports.getOrderById = function(args, res, next) { **/ var examples = {}; examples['application/json'] = { - "id" : 123456789, - "petId" : 123456789, - "complete" : true, - "status" : "aeiou", - "quantity" : 123, - "shipDate" : "2000-01-23T04:56:07.000+00:00" + "petId" : 2, + "quantity" : 9, + "id" : 5, + "shipDate" : "2000-01-23T04:56:07.000+00:00", + "complete" : false, + "status" : "placed" }; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); @@ -65,12 +65,12 @@ exports.placeOrder = function(args, res, next) { **/ var examples = {}; examples['application/json'] = { - "id" : 123456789, - "petId" : 123456789, - "complete" : true, - "status" : "aeiou", - "quantity" : 123, - "shipDate" : "2000-01-23T04:56:07.000+00:00" + "petId" : 5, + "quantity" : 5, + "id" : 1, + "shipDate" : "2000-01-23T04:56:07.000+00:00", + "complete" : false, + "status" : "placed" }; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json'); diff --git a/samples/server/petstore/nodejs/controllers/UserService.js b/samples/server/petstore/nodejs/controllers/UserService.js index 99090323f78..762b3455f61 100644 --- a/samples/server/petstore/nodejs/controllers/UserService.js +++ b/samples/server/petstore/nodejs/controllers/UserService.js @@ -54,14 +54,14 @@ exports.getUserByName = function(args, res, next) { **/ var examples = {}; examples['application/json'] = { - "id" : 123456789, - "lastName" : "aeiou", - "phone" : "aeiou", - "username" : "aeiou", - "email" : "aeiou", - "userStatus" : 123, "firstName" : "aeiou", - "password" : "aeiou" + "lastName" : "aeiou", + "password" : "aeiou", + "userStatus" : 4, + "phone" : "aeiou", + "id" : 5, + "email" : "aeiou", + "username" : "aeiou" }; if (Object.keys(examples).length > 0) { res.setHeader('Content-Type', 'application/json');