Skip to content

Commit 004d435

Browse files
committed
Fixes to more accurately use the url mappings
This change re-introduces format. We let the url mappings dictate what parameters to use and what to note use. (10)
1 parent 2d38d13 commit 004d435

34 files changed

+745
-435
lines changed

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

Lines changed: 349 additions & 248 deletions
Large diffs are not rendered by default.

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
import org.springframework.web.method.HandlerMethod;
88
import springfox.documentation.service.ResolvedMethodParameter;
99

10+
import java.util.Collection;
1011
import java.util.List;
1112
import java.util.Set;
1213

1314
class ActionSpecification {
14-
private final Set<RequestMethod> supportedMethods;
15+
private final Collection<RequestMethod> supportedMethods;
1516
private final Set<MediaType> produces;
1617
private final Set<MediaType> consumes;
1718
private final List<ResolvedMethodParameter> parameters;
@@ -21,7 +22,7 @@ class ActionSpecification {
2122

2223
public ActionSpecification(
2324
String path,
24-
Set<RequestMethod> supportedMethods,
25+
Collection<RequestMethod> supportedMethods,
2526
Set<MediaType> produces,
2627
Set<MediaType> consumes,
2728
HandlerMethod handlerMethod,
@@ -43,7 +44,7 @@ public String getPath() {
4344
return path;
4445
}
4546

46-
public Set<RequestMethod> getSupportedMethods() {
47+
public Collection<RequestMethod> getSupportedMethods() {
4748
return supportedMethods;
4849
}
4950

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public CreateActionSpecificationFactory(TypeResolver resolver) {
1717
public ActionSpecification create(GrailsActionContext context) {
1818
return new ActionSpecification(
1919
context.path(),
20-
Collections.singleton(context.getRequestMethod()),
20+
context.getRequestMethods(),
2121
context.supportedMediaTypes(),
2222
context.supportedMediaTypes(),
2323
context.handlerMethod(),

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@
22

33
import com.fasterxml.classmate.TypeResolver;
44

5-
import java.util.Collections;
6-
7-
import static springfox.documentation.grails.Parameters.*;
8-
95
class DeleteActionSpecificationFactory implements ActionSpecificationFactory {
106
private final TypeResolver resolver;
117

@@ -17,15 +13,11 @@ public DeleteActionSpecificationFactory(TypeResolver resolver) {
1713
public ActionSpecification create(GrailsActionContext context) {
1814
return new ActionSpecification(
1915
context.path(),
20-
Collections.singleton(context.getRequestMethod()),
16+
context.getRequestMethods(),
2117
context.supportedMediaTypes(),
2218
context.supportedMediaTypes(),
2319
context.handlerMethod(),
24-
Collections.singletonList(
25-
pathParameter(
26-
1,
27-
"id",
28-
resolver.resolve(idType(context.getDomainClass())))),
20+
context.pathParameters(),
2921
resolver.resolve(domainClass(context.getDomainClass())));
3022

3123
}

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@
22

33
import com.fasterxml.classmate.TypeResolver;
44

5-
import java.util.ArrayList;
6-
import java.util.Arrays;
7-
import java.util.Collections;
8-
9-
import static springfox.documentation.grails.Parameters.*;
10-
115
class EditActionSpecificationFactory implements ActionSpecificationFactory {
126
private final TypeResolver resolver;
137

@@ -19,13 +13,11 @@ public EditActionSpecificationFactory(TypeResolver resolver) {
1913
public ActionSpecification create(GrailsActionContext context) {
2014
return new ActionSpecification(
2115
context.path(),
22-
Collections.singleton(context.getRequestMethod()),
16+
context.getRequestMethods(),
2317
context.supportedMediaTypes(),
2418
context.supportedMediaTypes(),
2519
context.handlerMethod(),
26-
new ArrayList<>(Arrays.asList(
27-
pathParameter(1, "id", resolver.resolve(idType(context.getDomainClass()))),
28-
bodyParameter(2, resolver.resolve(domainClass(context.getDomainClass()))))),
20+
context.pathParameters(),
2921
resolver.resolve(domainClass(context.getDomainClass())));
3022

3123
}

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

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,37 @@
66
import org.springframework.beans.factory.annotation.Autowired;
77
import org.springframework.stereotype.Component;
88
import org.springframework.web.bind.annotation.RequestMethod;
9+
import org.springframework.web.servlet.mvc.condition.RequestCondition;
910

1011
import java.util.Arrays;
12+
import java.util.Collection;
1113
import java.util.Collections;
14+
import java.util.Comparator;
15+
import java.util.List;
1216
import java.util.Map;
1317
import java.util.Objects;
1418
import java.util.Optional;
1519
import java.util.Set;
1620
import java.util.function.Predicate;
1721
import java.util.stream.Collectors;
22+
import java.util.stream.Stream;
1823

24+
import static com.google.common.collect.Lists.*;
25+
import static springfox.documentation.builders.BuilderDefaults.*;
1926
import static springfox.documentation.grails.Actions.*;
2027

2128
@Component
2229
class GrailsActionAttributes {
30+
private static final List<RequestMethod> ALL_HTTP_METHODS = newArrayList(
31+
RequestMethod.GET,
32+
RequestMethod.POST,
33+
RequestMethod.PUT,
34+
RequestMethod.PATCH,
35+
RequestMethod.DELETE,
36+
RequestMethod.HEAD,
37+
RequestMethod.OPTIONS,
38+
RequestMethod.TRACE);
39+
2340
public static Map<String, String> methodMap = ImmutableMap.<String, String>builder()
2441
.put("index", "GET")
2542
.put("show", "GET")
@@ -30,7 +47,7 @@ class GrailsActionAttributes {
3047
.put("patch", "PATCH")
3148
.put("delete", "DELETE")
3249
.build();
33-
50+
3451
private final LinkGenerator linkGenerator;
3552
private final grails.web.mapping.UrlMappings urlMappings;
3653

@@ -42,26 +59,37 @@ public GrailsActionAttributes(
4259
this.urlMappings = urlMappings;
4360
}
4461

45-
public Set<RequestMethod> httpMethod(GrailsActionContext context) {
62+
public Collection<RequestMethod> httpMethods(GrailsActionContext context) {
4663
Set<RequestMethod> requestMethods = methodOverrides(context);
4764
if (requestMethods.isEmpty()) {
48-
Set<RequestMethod> defaultMethods = Arrays.stream(urlMappings.getUrlMappings())
49-
.filter(mapping ->
50-
Objects.equals(mapping.getControllerName(), context.getController().getName())
51-
&& Objects.equals(mapping.getActionName(), context.getAction()))
52-
.map(mapping -> RequestMethod.valueOf(mapping.getHttpMethod()))
53-
.collect(Collectors.toSet());
54-
if (defaultMethods.isEmpty()) {
55-
String defaultMethod = context.isRestfulController()
56-
? methodMap.getOrDefault(context.getAction(), "POST")
57-
: "POST";
58-
return Collections.singleton(RequestMethod.valueOf(defaultMethod));
59-
}
60-
return defaultMethods;
65+
Stream<UrlMapping> sorted = Arrays.stream(urlMappings.getUrlMappings())
66+
.filter(UrlMappings.selector(context, null))
67+
.sorted(Comparator.comparing(this::score));
68+
return sorted.findFirst()
69+
.map(m -> httpMethods(defaultIfAbsent(m.getHttpMethod(), "*")))
70+
.orElse(Collections.singleton(RequestMethod.OPTIONS));
6171
}
6272
return requestMethods;
6373
}
6474

75+
private Integer score(UrlMapping mapping) {
76+
String method = defaultIfAbsent(mapping.getHttpMethod(), "*");
77+
String action = Optional.ofNullable(mapping.getActionName())
78+
.map(Object::toString)
79+
.orElse("*");
80+
81+
int methodScore = method.equals("*") ? 1000 : 0;
82+
int actionScore = action.equals("*") ? 1000 : 0;
83+
return (actionScore * 10) + methodScore;
84+
}
85+
86+
private Collection<RequestMethod> httpMethods(String httpMethod) {
87+
if (Objects.equals(httpMethod, "*")) {
88+
return ALL_HTTP_METHODS;
89+
}
90+
return Collections.singleton(RequestMethod.valueOf(httpMethod));
91+
}
92+
6593
public boolean isRestfulAction(String action) {
6694
return methodMap.containsKey(action);
6795
}
@@ -80,7 +108,6 @@ public String actionUrl(GrailsActionContext context, UrlMapping mapping) {
80108
"UTF-8")
81109
.replace("%7B", "{").replace("%7D", "}")
82110
.replace(linkGenerator.getServerBaseURL(), "")
83-
.replace(".{format}", "")
84111
.toLowerCase();
85112
}
86113

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.springframework.web.method.HandlerMethod;
1111
import springfox.documentation.service.ResolvedMethodParameter;
1212

13+
import java.util.Collection;
1314
import java.util.List;
1415
import java.util.Map;
1516
import java.util.Optional;
@@ -27,8 +28,9 @@ class GrailsActionContext {
2728
private final TypeResolver resolver;
2829
private final Optional<UrlMapping> urlMapping;
2930
private final boolean isRestfulController;
30-
private final String method;
3131
private final Set<MediaType> mediaTypes;
32+
private final Collection<RequestMethod> requestMethods;
33+
private final boolean missingMapping;
3234

3335
public GrailsActionContext(
3436
GrailsControllerClass controller,
@@ -42,11 +44,13 @@ public GrailsActionContext(
4244
this.action = action;
4345
this.resolver = resolver;
4446
this.isRestfulController = isRestfulController(controller, action);
45-
this.method = urlProvider.httpMethod(this)
47+
this.requestMethods = urlProvider.httpMethods(this);
48+
String method = requestMethods
4649
.stream()
4750
.findFirst()
4851
.map(Enum::toString)
4952
.orElse(null);
53+
this.missingMapping = requestMethods.isEmpty();
5054
this.urlMapping = urlProvider.urlMapping(selector(this, method));
5155
this.mediaTypes = mediaTypeOverrides(this);
5256
maybeAddDefaultMediaType(mediaTypes);
@@ -86,8 +90,8 @@ public List<ResolvedMethodParameter> pathParameters() {
8690
.orElse(newArrayList());
8791
}
8892

89-
public RequestMethod getRequestMethod() {
90-
return RequestMethod.valueOf(method);
93+
public Collection<RequestMethod> getRequestMethods() {
94+
return requestMethods;
9195
}
9296

9397
public HandlerMethod handlerMethod() {
@@ -103,6 +107,10 @@ public boolean isRestfulController() {
103107
return isRestfulController;
104108
}
105109

110+
public boolean isMissingMapping() {
111+
return missingMapping;
112+
}
113+
106114
private boolean isRestfulController(GrailsControllerClass controller, String action) {
107115
try {
108116
Class<?> restfulController = Class.forName("grails.rest.RestfulController");

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.classmate.ResolvedType;
44
import com.google.common.base.Optional;
5+
import com.google.common.collect.ImmutableSet;
56
import org.springframework.core.annotation.AnnotationUtils;
67
import org.springframework.http.MediaType;
78
import org.springframework.web.bind.annotation.RequestMethod;
@@ -65,7 +66,7 @@ public String getName() {
6566

6667
@Override
6768
public Set<RequestMethod> supportedMethods() {
68-
return actionSpecification.getSupportedMethods();
69+
return ImmutableSet.copyOf(actionSpecification.getSupportedMethods());
6970
}
7071

7172
@Override
Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package springfox.documentation.grails;
22

33
import com.fasterxml.classmate.TypeResolver;
4-
import org.springframework.http.MediaType;
54
import springfox.documentation.service.ResolvedMethodParameter;
65

7-
import java.util.Collections;
86
import java.util.List;
9-
import java.util.Set;
107

118
import static com.google.common.collect.Lists.*;
129
import static springfox.documentation.grails.Parameters.*;
@@ -22,27 +19,22 @@ public IndexActionSpecificationFactory(TypeResolver resolver) {
2219
public ActionSpecification create(GrailsActionContext context) {
2320
return new ActionSpecification(
2421
context.path(),
25-
Collections.singleton(context.getRequestMethod()),
22+
context.getRequestMethods(),
2623
context.supportedMediaTypes(),
2724
context.supportedMediaTypes(),
2825
context.handlerMethod(),
29-
parameters(context.supportedMediaTypes()),
26+
parameters(context),
3027
resolver.resolve(List.class, domainClass(context.getDomainClass())));
3128
}
3229

33-
private List<ResolvedMethodParameter> parameters(Set<MediaType> mediaTypes) {
34-
List<ResolvedMethodParameter> parameters = newArrayList(queryParameter(
35-
0,
30+
private List<ResolvedMethodParameter> parameters(GrailsActionContext context) {
31+
List<ResolvedMethodParameter> parameters = newArrayList(context.pathParameters());
32+
parameters.add(queryParameter(
33+
1,
3634
"max",
3735
resolver.resolve(Integer.class),
3836
false,
3937
""));
40-
if (mediaTypes.size() > 1) {
41-
parameters.add(pathParameter(
42-
1,
43-
"format",
44-
resolver.resolve(String.class)));
45-
}
4638
return parameters;
4739
}
4840
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import springfox.documentation.spring.web.readers.operation.HandlerMethodResolver;
88

99
import java.util.ArrayList;
10-
import java.util.Collections;
1110
import java.util.List;
1211

1312
@Component
@@ -25,7 +24,7 @@ public ActionSpecification create(GrailsActionContext context) {
2524
methodParameters.addAll(handlerMethodResolver.methodParameters(context.handlerMethod()));
2625
return new ActionSpecification(
2726
context.path(),
28-
Collections.singleton(context.getRequestMethod()),
27+
context.getRequestMethods(),
2928
context.supportedMediaTypes(),
3029
context.supportedMediaTypes(),
3130
context.handlerMethod(),

0 commit comments

Comments
 (0)