Skip to content

Commit

Permalink
Merge pull request #3176 from kremers/form-fix
Browse files Browse the repository at this point in the history
Create a FormParameter model object instead of BodyParameter

related to #2722
  • Loading branch information
dilipkrish committed Jan 6, 2020
2 parents 650ef94 + bbda544 commit 45373e6
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import io.swagger.models.ModelImpl;
import io.swagger.models.RefModel;
import io.swagger.models.parameters.BodyParameter;
import io.swagger.models.parameters.FormParameter;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.FileProperty;
import io.swagger.models.properties.Property;
Expand All @@ -37,19 +38,73 @@
import java.util.List;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import static springfox.documentation.schema.Types.*;
import static springfox.documentation.swagger2.mappers.EnumMapper.*;
import static springfox.documentation.swagger2.mappers.Properties.*;
import static java.util.stream.Collectors.toSet;
import static springfox.documentation.schema.Types.isBaseType;
import static springfox.documentation.swagger2.mappers.EnumMapper.maybeAddAllowableValues;
import static springfox.documentation.swagger2.mappers.EnumMapper.maybeAddAllowableValuesToParameter;
import static springfox.documentation.swagger2.mappers.Properties.itemTypeProperty;
import static springfox.documentation.swagger2.mappers.Properties.property;

@Mapper
public class ParameterMapper {

// This list is directly copied from the OpenAPI 2.0 spec
private static final Set<String> SUPPORTED_FORM_DATA_TYPES = Stream.of(
"string",
"number",
"integer",
"boolean",
"array",
"file").collect(toSet());

private static final VendorExtensionsMapper VENDOR_EXTENSIONS_MAPPER = new VendorExtensionsMapper();

public Parameter mapParameter(springfox.documentation.service.Parameter source) {
Parameter bodyParameter = bodyParameter(source);
return SerializableParameterFactories.create(source).orElse(bodyParameter);
Parameter parameter;
if ("formData".equals(source.getParamType())) {
parameter = formParameter(source);
} else {
parameter = bodyParameter(source);
}
return SerializableParameterFactories.create(source).orElse(parameter);
}

private Parameter formParameter(springfox.documentation.service.Parameter source) {

FormParameter parameter = new FormParameter()
.name(source.getName())
.description(source.getDescription());

// Form Parameters only work with certain primitive types specified in the spec
ModelReference modelRef = source.getModelRef();
parameter.setProperty(itemTypeProperty(modelRef));

if (!SUPPORTED_FORM_DATA_TYPES.contains(parameter.getType())
|| "array".equals(parameter.getType())
&& !SUPPORTED_FORM_DATA_TYPES.contains(parameter.getItems().getType())) {
// Falling back to BodyParameter is non-compliant with the Swagger 2.0 spec,
// but matches previous behavior.
return bodyParameter(source);
}

parameter.setIn(source.getParamType());
parameter.setAccess(source.getParamAccess());
parameter.setPattern(source.getPattern());
parameter.setRequired(source.isRequired());
parameter.getVendorExtensions().putAll(VENDOR_EXTENSIONS_MAPPER.mapExtensions(source.getVendorExtentions()));
for (Entry<String, List<Example>> each : source.getExamples().entrySet()) {
Optional<Example> example = each.getValue().stream().findFirst();
if (example.isPresent() && example.get().getValue() != null) {
// Form parameters only support a single example
parameter.example(String.valueOf(example.get().getValue()));
break;
}
}

return parameter;
}

private Parameter bodyParameter(springfox.documentation.service.Parameter source) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package springfox.documentation.swagger2.mappers
import com.fasterxml.classmate.ResolvedType
import io.swagger.models.Model
import io.swagger.models.parameters.BodyParameter
import io.swagger.models.parameters.FormParameter
import io.swagger.models.parameters.QueryParameter
import io.swagger.models.parameters.SerializableParameter
import io.swagger.models.properties.FileProperty
import spock.lang.Specification
import springfox.documentation.builders.ParameterBuilder
import springfox.documentation.schema.ModelRef
Expand Down Expand Up @@ -37,6 +39,66 @@ class ParameterMapperSpec extends Specification {
"body" | new ModelRef("sometype", new ModelRef("itemType"), true) | BodyParameter
}

def "form parameters are mapped correctly" () {
given:
def parameter = parameter("formData").modelRef(modelRef).build()
when:
def sut = new ParameterMapper()
then:
def mapped = (FormParameter) sut.mapParameter(parameter)
and:
mapped.access == "access"
mapped.name == "test"
mapped.description == "test description"
mapped.required
mapped.type == type
mapped.format == format
mapped.items?.format == itemFormat
mapped.items?.type == itemType

where:
modelRef | type | format | itemType | itemFormat
new ModelRef("string") | "string" | null | null | null
new ModelRef("array", new ModelRef("string")) | "array" | null | "string" | null
new ModelRef("array", new ModelRef("int")) | "array" | null | "integer" | "int32"
new ModelRef("int") | "integer" | "int32" | null | null
new ModelRef("long") | "integer" | "int64" | null | null
new ModelRef("boolean") | "boolean" | null | null | null
}

def "form parameters fall back to body parameters for non-primitive top level types" () {
given:
def parameter = parameter("formData")
.modelRef(new ModelRef("some-non-primitive-type"))
.build()
when:
def sut = new ParameterMapper()
then:
sut.mapParameter(parameter) instanceof BodyParameter
}

def "file parameter handling" () {
given:
def parameter = parameter("formData")
.modelRef(new ModelRef("file"))
.build()
when:
def sut = new ParameterMapper()
then:
sut.mapParameter(parameter) instanceof BodyParameter
}

def "form parameters fall back to body parameters for arrays of non-primitive types" () {
given:
def parameter = parameter("formData")
.modelRef(new ModelRef("array", new ModelRef("object")))
.build()
when:
def sut = new ParameterMapper()
then:
sut.mapParameter(parameter) instanceof BodyParameter
}

def "Serializes byte array to string model in body" () {
given:
def byteArray = new ModelRef("", new ModelRef("byte"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1119,10 +1119,8 @@
"name": "sfId",
"description": "sfId",
"required": true,
"schema": {
"type": "integer",
"format": "int32"
}
"type": "integer",
"format": "int32"
}
],
"responses": {
Expand Down Expand Up @@ -1152,92 +1150,72 @@
"name": "allCapsSet",
"description": "description of allCapsSet",
"required": false,
"schema": {
"type": "array",
"items": {
"type": "string"
}
}
"type": "array",
"items": {
"type": "string"
},
"collectionFormat": "multi"
},
{
"in": "formData",
"name": "annotatedEnumType",
"description": "description of annotatedEnumType",
"required": false,
"schema": {
"type": "string"
}
"type": "string"
},
{
"in": "formData",
"name": "bar",
"description": "description of bar",
"required": false,
"schema": {
"type": "integer",
"format": "int32",
"example": "10"
}
"type": "integer",
"format": "int32"
},
{
"in": "formData",
"name": "enumType",
"required": false,
"schema": {
"type": "string"
}
"type": "string"
},
{
"in": "formData",
"name": "foo",
"description": "description of foo",
"required": true,
"schema": {
"type": "string"
}
"type": "string"
},
{
"in": "formData",
"name": "localDateTime",
"description": "local date time desc dd-MM-yyyy hh:mm:ss",
"required": true,
"schema": {
"type": "string",
"format": "date-time"
}
"type": "string",
"format": "date-time"
},
{
"in": "formData",
"name": "nestedType.name",
"required": false,
"schema": {
"type": "string"
}
"type": "string"
},
{
"in": "formData",
"name": "parentBeanProperty",
"required": false,
"schema": {
"type": "string"
}
"type": "string"
},
{
"in": "formData",
"name": "propertyWithNoSetterMethod",
"required": false,
"schema": {
"type": "string"
}
"type": "string"
},
{
"in": "formData",
"name": "readOnlyString",
"description": "A read only string",
"required": false,
"schema": {
"type": "string"
}
"type": "string"
}
],
"responses": {
Expand Down Expand Up @@ -1466,8 +1444,8 @@
"/bugs/2268{?$filter}": {
"get": {
"tags": [
"example",
"Bugs"
"Bugs",
"example"
],
"summary": "Get all examples",
"description": "Get all examples ",
Expand Down Expand Up @@ -2518,4 +2496,4 @@
"title": "UpperCasedField"
}
}
}
}

0 comments on commit 45373e6

Please sign in to comment.