Skip to content

Commit 330291b

Browse files
committed
Fixes generation of optional path paramters
Swagger does not support optional path parameters as of 2.0. So we skip renderering them alltogether. fixes #11
1 parent ae65c62 commit 330291b

File tree

10 files changed

+126
-401
lines changed

10 files changed

+126
-401
lines changed

springfox-grails-contract-tests/src/integration-test/resources/expected-service-description.json

Lines changed: 57 additions & 299 deletions
Large diffs are not rendered by default.

springfox-grails/src/main/java/springfox/documentation/grails/UrlMappings.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ private static IntPredicate indicesToUse(UrlMapping mapping) {
7070
return index -> {
7171
ConstrainedProperty property = mapping.getConstraints()[index];
7272
return !property.getPropertyName().equals("controller")
73-
&& !property.getPropertyName().equals("action");
73+
&& !property.getPropertyName().equals("action")
74+
&& !property.isNullable();
7475
};
7576
}
7677

springfox-grails/src/test/groovy/springfox/documentation/grails/DeleteActionSpecificationFactorySpec.groovy

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,15 @@ class DeleteActionSpecificationFactorySpec extends ActionSpecificationFactorySpe
1818
spec.produces == [MediaType.APPLICATION_JSON] as Set
1919
spec.supportedMethods == [RequestMethod.DELETE] as Set
2020
spec.handlerMethod.method == AController.methods.find {it.name == "delete" }
21-
spec.path == "/a/{id}.{format}"
21+
spec.path == "/a/{id}"
2222

2323
and: "Parameters match"
24-
spec.parameters.size() == 2
24+
spec.parameters.size() == 1
2525
spec.parameters[0].parameterType == resolver.resolve(Long)
2626
spec.parameters[0].parameterIndex == 0
2727
spec.parameters[0].defaultName().isPresent()
2828
spec.parameters[0].defaultName().get() == "id"
2929

30-
spec.parameters[1].parameterType == resolver.resolve(String)
31-
spec.parameters[1].parameterIndex == 1
32-
spec.parameters[1].defaultName().isPresent()
33-
spec.parameters[1].defaultName().get() == "format"
34-
3530
and: "Return type matches"
3631
spec.returnType == resolver.resolve(ADomain)
3732
}

springfox-grails/src/test/groovy/springfox/documentation/grails/GrailsActionContextSpec.groovy

Lines changed: 40 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -29,46 +29,46 @@ class GrailsActionContextSpec extends Specification implements UrlMappingSupport
2929
sut.requestMethods == (method == "" ? [] as Set : [RequestMethod.valueOf(method)] as Set)
3030

3131
where:
32-
controller | action | params | method | path
33-
"author" | "index" | ["novelId", "format"] | "GET" | "/novels/{novelid}/authors?format={format}"
34-
"author" | "update" | ["novelId", "id", "format"] | "PUT" | "/novels/{novelid}/authors/{id}?format={format}"
35-
"author" | "create" | ["novelId"] | "GET" | "/novels/{novelid}/authors/create"
36-
"author" | "show" | ["novelId", "id", "format"] | "GET" | "/novels/{novelid}/authors/{id}?format={format}"
37-
"author" | "save" | ["novelId", "format"] | "POST" | "/novels/{novelid}/authors?format={format}"
38-
"author" | "edit" | ["novelId", "id"] | "GET" | "/novels/{novelid}/authors/{id}/edit"
39-
"author" | "delete" | ["novelId", "id", "format"] | "DELETE" | "/novels/{novelid}/authors/{id}?format={format}"
40-
"artist" | "index" | ["format"] | "GET" | "/artists?format={format}"
41-
"artist" | "update" | ["id", "format"] | "PUT" | "/artist/{id}.{format}"
42-
"artist" | "delete" | ["id", "format"] | "DELETE" | "/artist/{id}.{format}"
43-
"artist" | "create" | [] | "" | "/artist/create"
44-
"artist" | "show" | ["id", "format"] | "GET" | "/artists/{id}?format={format}"
45-
"artist" | "save" | ["format"] | "POST" | "/artist.{format}"
46-
"artist" | "edit" | ["id"] | "GET" | "/artist/{id}/edit"
47-
"album" | "index" | ["format"] | "GET" | "/albums?format={format}"
48-
"album" | "update" | ["id", "format"] | "PUT" | "/album/{id}.{format}"
49-
"album" | "delete" | ["id", "format"] | "DELETE" | "/album/{id}.{format}"
50-
"album" | "create" | [] | "GET" | "/albums/create"
51-
"album" | "show" | ["id", "format"] | "GET" | "/albums/{id}?format={format}"
52-
"album" | "save" | ["format"] | "POST" | "/albums?format={format}"
53-
"album" | "edit" | ["id"] | "GET" | "/albums/{id}/edit"
54-
"book" | "index" | ["format"] | "GET" | "/books?format={format}"
55-
"book" | "update" | ["id", "format"] | "PUT" | "/books/{id}?format={format}"
56-
"book" | "delete" | ["id", "format"] | "DELETE" | "/books/{id}?format={format}"
57-
"book" | "create" | [] | "GET" | "/books/create"
58-
"book" | "show" | ["id", "format"] | "GET" | "/books/{id}?format={format}"
59-
"book" | "save" | ["format"] | "POST" | "/books?format={format}"
60-
"book" | "edit" | ["id"] | "GET" | "/books/{id}/edit"
61-
"product" | "list" | [] | "GET" | "/product"
62-
"product" | "other" | [] | "" | "/product/other"
63-
"product" | null | ["id"] | "GET" | "/store/product/{id}"
64-
"generic" | "index" | ["format"] | "GET" | "/generic.{format}"
65-
"generic" | "update" | ["id", "format"] | "PUT" | "/generic/{id}.{format}"
66-
"generic" | "delete" | ["id", "format"] | "DELETE" | "/generic/{id}.{format}"
67-
"generic" | "create" | [] | "" | "/generic/create"
68-
"generic" | "show" | ["id", "format"] | "GET" | "/generic/{id}.{format}"
69-
"generic" | "save" | ["format"] | "POST" | "/generic.{format}"
70-
"generic" | "edit" | ["id"] | "GET" | "/generic/{id}/edit"
71-
"generic" | "other" | [] | "" | "/generic/other"
32+
controller | action | params | method | path
33+
"author" | "index" | ["novelId"] | "GET" | "/novels/{novelid}/authors"
34+
"author" | "update" | ["novelId", "id"] | "PUT" | "/novels/{novelid}/authors/{id}"
35+
"author" | "create" | ["novelId"] | "GET" | "/novels/{novelid}/authors/create"
36+
"author" | "show" | ["novelId", "id"] | "GET" | "/novels/{novelid}/authors/{id}"
37+
"author" | "save" | ["novelId"] | "POST" | "/novels/{novelid}/authors"
38+
"author" | "edit" | ["novelId", "id"] | "GET" | "/novels/{novelid}/authors/{id}/edit"
39+
"author" | "delete" | ["novelId", "id"] | "DELETE" | "/novels/{novelid}/authors/{id}"
40+
"artist" | "index" | [] | "GET" | "/artists"
41+
"artist" | "update" | ["id"] | "PUT" | "/artist/{id}"
42+
"artist" | "delete" | ["id"] | "DELETE" | "/artist/{id}"
43+
"artist" | "create" | [] | "" | "/artist/create"
44+
"artist" | "show" | ["id"] | "GET" | "/artists/{id}"
45+
"artist" | "save" | [] | "POST" | "/artist"
46+
"artist" | "edit" | ["id"] | "GET" | "/artist/{id}/edit"
47+
"album" | "index" | [] | "GET" | "/albums"
48+
"album" | "update" | ["id"] | "PUT" | "/album/{id}"
49+
"album" | "delete" | ["id"] | "DELETE" | "/album/{id}"
50+
"album" | "create" | [] | "GET" | "/albums/create"
51+
"album" | "show" | ["id"] | "GET" | "/albums/{id}"
52+
"album" | "save" | [] | "POST" | "/albums"
53+
"album" | "edit" | ["id"] | "GET" | "/albums/{id}/edit"
54+
"book" | "index" | [] | "GET" | "/books"
55+
"book" | "update" | ["id"] | "PUT" | "/books/{id}"
56+
"book" | "delete" | ["id"] | "DELETE" | "/books/{id}"
57+
"book" | "create" | [] | "GET" | "/books/create"
58+
"book" | "show" | ["id"] | "GET" | "/books/{id}"
59+
"book" | "save" | [] | "POST" | "/books"
60+
"book" | "edit" | ["id"] | "GET" | "/books/{id}/edit"
61+
"product" | "list" | [] | "GET" | "/product"
62+
"product" | "other" | [] | "" | "/product/other"
63+
"product" | null | ["id"] | "GET" | "/store/product/{id}"
64+
"generic" | "index" | [] | "GET" | "/generic"
65+
"generic" | "update" | ["id"] | "PUT" | "/generic/{id}"
66+
"generic" | "delete" | ["id"] | "DELETE" | "/generic/{id}"
67+
"generic" | "create" | [] | "" | "/generic/create"
68+
"generic" | "show" | ["id"] | "GET" | "/generic/{id}"
69+
"generic" | "save" | [] | "POST" | "/generic"
70+
"generic" | "edit" | ["id"] | "GET" | "/generic/{id}/edit"
71+
"generic" | "other" | [] | "" | "/generic/other"
7272
}
7373

7474
def actionAttributes() {
@@ -85,7 +85,6 @@ class GrailsActionContextSpec extends Specification implements UrlMappingSupport
8585
GrailsDomainClass domain() {
8686
def mock = Mock(GrailsDomainClass)
8787
mock.getPropertyByName(_) >> { args -> property(args[0]) }
88-
mock.hasProperty(_) >> { args -> "format" != args[0] }
8988
mock
9089
}
9190

springfox-grails/src/test/groovy/springfox/documentation/grails/IndexActionSpecificationFactorySpec.groovy

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,15 @@ class IndexActionSpecificationFactorySpec extends ActionSpecificationFactorySpec
1818
spec.produces == [MediaType.APPLICATION_JSON] as Set
1919
spec.supportedMethods == [RequestMethod.GET] as Set
2020
spec.handlerMethod.method == RestfulController.declaredMethods.find {it.name == "index" }
21-
spec.path == "/a.{format}"
21+
spec.path == "/a"
2222

2323
and: "Parameters match"
24-
spec.parameters.size() == 2
25-
spec.parameters[0].parameterType == resolver.resolve(String)
26-
spec.parameters[0].parameterIndex == 0
27-
spec.parameters[0].defaultName().isPresent()
28-
spec.parameters[0].defaultName().get() == "format"
24+
spec.parameters.size() == 1
2925

30-
spec.parameters[1].parameterType == resolver.resolve(Integer)
31-
spec.parameters[1].parameterIndex == 1
32-
spec.parameters[1].defaultName().isPresent()
33-
spec.parameters[1].defaultName().get() == "max"
26+
spec.parameters[0].parameterType == resolver.resolve(Integer)
27+
spec.parameters[0].parameterIndex == 1
28+
spec.parameters[0].defaultName().isPresent()
29+
spec.parameters[0].defaultName().get() == "max"
3430

3531
and: "Return type matches"
3632
spec.returnType == resolver.resolve(List, ADomain)

springfox-grails/src/test/groovy/springfox/documentation/grails/MethodBackedActionSpecificationFactorySpec.groovy

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,15 @@ class MethodBackedActionSpecificationFactorySpec extends ActionSpecificationFact
2020
spec.produces == [MediaType.APPLICATION_JSON] as Set
2121
spec.supportedMethods == [RequestMethod.POST] as Set
2222
spec.handlerMethod.method == BookController.methods.find {it.name == "save" }
23-
spec.path == "/book.{format}"
23+
spec.path == "/book"
2424

2525
and: "Parameters match"
26-
spec.parameters.size() == 2
27-
spec.parameters[0].parameterType == resolver.resolve(String)
26+
spec.parameters.size() == 1
27+
28+
spec.parameters[0].parameterType == resolver.resolve(Book)
2829
spec.parameters[0].parameterIndex == 0
2930
spec.parameters[0].defaultName().isPresent()
30-
spec.parameters[0].defaultName().get() == "format"
31-
32-
spec.parameters[1].parameterType == resolver.resolve(Book)
33-
spec.parameters[1].parameterIndex == 0
34-
spec.parameters[1].defaultName().isPresent()
35-
spec.parameters[1].defaultName().get() == "book"
31+
spec.parameters[0].defaultName().get() == "book"
3632

3733
and: "Return type matches"
3834
spec.returnType == resolver.resolve(Object)

springfox-grails/src/test/groovy/springfox/documentation/grails/PatchActionSpecificationFactorySpec.groovy

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,19 @@ class PatchActionSpecificationFactorySpec extends ActionSpecificationFactorySpec
1717
spec.produces == [MediaType.APPLICATION_JSON] as Set
1818
spec.supportedMethods == [RequestMethod.PATCH] as Set
1919
spec.handlerMethod.method == AController.methods.find { it.name == "patch" }
20-
spec.path == "/a/{id}.{format}"
20+
spec.path == "/a/{id}"
2121

2222
and: "Parameters match"
23-
spec.parameters.size() == 3
23+
spec.parameters.size() == 2
2424
spec.parameters[0].parameterType == resolver.resolve(Long)
2525
spec.parameters[0].parameterIndex == 0
2626
spec.parameters[0].defaultName().isPresent()
2727
spec.parameters[0].defaultName().get() == "id"
2828

29-
spec.parameters[1].parameterType == resolver.resolve(String)
29+
spec.parameters[1].parameterType == resolver.resolve(ADomain)
3030
spec.parameters[1].parameterIndex == 1
3131
spec.parameters[1].defaultName().isPresent()
32-
spec.parameters[1].defaultName().get() == "format"
33-
34-
spec.parameters[2].parameterType == resolver.resolve(ADomain)
35-
spec.parameters[2].parameterIndex == 2
36-
spec.parameters[2].defaultName().isPresent()
37-
spec.parameters[2].defaultName().get() == "body"
32+
spec.parameters[1].defaultName().get() == "body"
3833

3934
and: "Return type matches"
4035
spec.returnType == resolver.resolve(ADomain)

springfox-grails/src/test/groovy/springfox/documentation/grails/SaveActionSpecificationFactorySpec.groovy

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,14 @@ class SaveActionSpecificationFactorySpec extends ActionSpecificationFactorySpec
1818
spec.produces == [MediaType.APPLICATION_JSON] as Set
1919
spec.supportedMethods == [RequestMethod.POST] as Set
2020
spec.handlerMethod.method == AController.methods.find {it.name == "save" }
21-
spec.path == "/a.{format}"
21+
spec.path == "/a"
2222

2323
and: "Parameters match"
24-
spec.parameters.size() == 2
25-
spec.parameters[0].parameterType == resolver.resolve(String)
24+
spec.parameters.size() == 1
25+
spec.parameters[0].parameterType == resolver.resolve(ADomain)
2626
spec.parameters[0].parameterIndex == 0
2727
spec.parameters[0].defaultName().isPresent()
28-
spec.parameters[0].defaultName().get() == "format"
29-
30-
spec.parameters[1].parameterType == resolver.resolve(ADomain)
31-
spec.parameters[1].parameterIndex == 1
32-
spec.parameters[1].defaultName().isPresent()
33-
spec.parameters[1].defaultName().get() == "body"
28+
spec.parameters[0].defaultName().get() == "body"
3429

3530
and: "Return type matches"
3631
spec.returnType == resolver.resolve(ADomain)

springfox-grails/src/test/groovy/springfox/documentation/grails/ShowActionSpecificationFactorySpec.groovy

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,15 @@ class ShowActionSpecificationFactorySpec extends ActionSpecificationFactorySpec
1717
spec.produces == [MediaType.APPLICATION_JSON] as Set
1818
spec.supportedMethods == [RequestMethod.GET] as Set
1919
spec.handlerMethod.method == AController.methods.find {it.name == "show" }
20-
spec.path == "/a/{id}.{format}"
20+
spec.path == "/a/{id}"
2121

2222
and: "Parameters match"
23-
spec.parameters.size() == 2
23+
spec.parameters.size() == 1
2424
spec.parameters[0].parameterType == resolver.resolve(Long)
2525
spec.parameters[0].parameterIndex == 0
2626
spec.parameters[0].defaultName().isPresent()
2727
spec.parameters[0].defaultName().get() == "id"
2828

29-
spec.parameters[1].parameterType == resolver.resolve(String)
30-
spec.parameters[1].parameterIndex == 1
31-
spec.parameters[1].defaultName().isPresent()
32-
spec.parameters[1].defaultName().get() == "format"
33-
3429
and: "Return type matches"
3530
spec.returnType == resolver.resolve(ADomain)
3631
}

springfox-grails/src/test/groovy/springfox/documentation/grails/UpdateActionSpecificationFactorySpec.groovy

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,19 @@ class UpdateActionSpecificationFactorySpec extends ActionSpecificationFactorySpe
1818
spec.produces == [MediaType.APPLICATION_JSON] as Set
1919
spec.supportedMethods == [RequestMethod.PUT] as Set
2020
spec.handlerMethod.method == AController.methods.find {it.name == "update" }
21-
spec.path == "/a/{id}.{format}"
21+
spec.path == "/a/{id}"
2222

2323
and: "Parameters match"
24-
spec.parameters.size() == 3
24+
spec.parameters.size() == 2
2525
spec.parameters[0].parameterType == resolver.resolve(Long)
2626
spec.parameters[0].parameterIndex == 0
2727
spec.parameters[0].defaultName().isPresent()
2828
spec.parameters[0].defaultName().get() == "id"
2929

30-
spec.parameters[1].parameterType == resolver.resolve(String)
30+
spec.parameters[1].parameterType == resolver.resolve(ADomain)
3131
spec.parameters[1].parameterIndex == 1
3232
spec.parameters[1].defaultName().isPresent()
33-
spec.parameters[1].defaultName().get() == "format"
34-
35-
spec.parameters[2].parameterType == resolver.resolve(ADomain)
36-
spec.parameters[2].parameterIndex == 2
37-
spec.parameters[2].defaultName().isPresent()
38-
spec.parameters[2].defaultName().get() == "body"
33+
spec.parameters[1].defaultName().get() == "body"
3934

4035
and: "Return type matches"
4136
spec.returnType == resolver.resolve(ADomain)

0 commit comments

Comments
 (0)