Skip to content

Commit e18679e

Browse files
committed
Functional DSL incorrect path mapping Fixes #980, #968.
1 parent 7c14f30 commit e18679e

File tree

6 files changed

+300
-100
lines changed

6 files changed

+300
-100
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/core/fn/AbstractRouterFunctionVisitor.java

Lines changed: 115 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,18 @@
2121
package org.springdoc.core.fn;
2222

2323
import java.util.ArrayList;
24-
import java.util.Arrays;
24+
import java.util.HashMap;
2525
import java.util.LinkedHashMap;
2626
import java.util.List;
2727
import java.util.Map;
2828
import java.util.Set;
29+
import java.util.stream.Collectors;
2930

3031
import org.apache.commons.lang3.StringUtils;
3132

3233
import org.springframework.http.HttpHeaders;
3334
import org.springframework.http.HttpMethod;
35+
import org.springframework.util.CollectionUtils;
3436

3537
/**
3638
* The type Abstract router function visitor.
@@ -46,50 +48,63 @@ public class AbstractRouterFunctionVisitor {
4648
/**
4749
* The Nested or paths.
4850
*/
49-
protected List<String> nestedOrPaths = new ArrayList<>();
51+
protected List<String> orPaths = new ArrayList<>();
5052

5153
/**
5254
* The Nested and paths.
5355
*/
54-
protected List<String> nestedAndPaths = new ArrayList<>();
56+
protected Map<Integer, List<String>> nestedPaths = new LinkedHashMap<>();
5557

5658
/**
57-
* The Nested accept headers.
59+
* The Is or.
5860
*/
59-
protected List<String> nestedAcceptHeaders = new ArrayList<>();
61+
protected boolean isOr;
6062

6163
/**
62-
* The Nested content type headers.
64+
* The Router function data.
6365
*/
64-
protected List<String> nestedContentTypeHeaders = new ArrayList<>();
66+
protected List<RouterFunctionData> currentRouterFunctionDatas;
6567

6668
/**
67-
* The Is or.
69+
* The Attributes.
6870
*/
69-
protected boolean isOr;
71+
protected Map<String, Object> attributes = new LinkedHashMap<>();
7072

7173
/**
72-
* The Is nested.
74+
* The Level.
7375
*/
74-
protected boolean isNested;
76+
private int level;
7577

7678
/**
77-
* The Router function data.
79+
* The Methods.
7880
*/
79-
protected RouterFunctionData routerFunctionData;
81+
private Set<HttpMethod> methods;
8082

8183
/**
82-
* The Attributes.
84+
* The Consumes.
8385
*/
84-
protected Map<String,Object> attributes = new LinkedHashMap<>();
86+
private final List<String> consumes = new ArrayList<>();
87+
88+
/**
89+
* The Produces.
90+
*/
91+
private final List<String> produces = new ArrayList<>();
92+
93+
/**
94+
* The Query params.
95+
*/
96+
private final Map<String, String> queryParams = new LinkedHashMap<>();
8597

8698
/**
8799
* Method.
88100
*
89101
* @param methods the methods
90102
*/
91103
public void method(Set<HttpMethod> methods) {
92-
routerFunctionData.setMethods(methods);
104+
if (CollectionUtils.isEmpty(currentRouterFunctionDatas))
105+
this.methods = methods;
106+
else
107+
currentRouterFunctionDatas.forEach(routerFunctionData -> routerFunctionData.setMethods(methods));
93108
}
94109

95110
/**
@@ -98,12 +113,26 @@ public void method(Set<HttpMethod> methods) {
98113
* @param pattern the pattern
99114
*/
100115
public void path(String pattern) {
101-
if (routerFunctionData != null)
102-
routerFunctionData.setPath(pattern);
116+
if (currentRouterFunctionDatas != null) {
117+
if (!nestedPaths.isEmpty()) {
118+
List<String> nestedPathsList = this.nestedPaths.values().stream().flatMap(List::stream).collect(Collectors.toList());
119+
if (!orPaths.isEmpty())
120+
orPaths.forEach(nestedOrPath -> createRouterFunctionData(String.join(StringUtils.EMPTY, nestedPathsList) + nestedOrPath + pattern));
121+
else
122+
createRouterFunctionData(String.join(StringUtils.EMPTY, nestedPathsList) + pattern);
123+
}
124+
else if (!orPaths.isEmpty())
125+
orPaths.forEach(nestedOrPath -> createRouterFunctionData(nestedOrPath + pattern));
126+
else
127+
createRouterFunctionData(pattern);
128+
}
103129
else if (isOr)
104-
nestedOrPaths.add(pattern);
105-
else if (isNested)
106-
nestedAndPaths.add(pattern);
130+
orPaths.add(pattern);
131+
else if (this.level > 0) {
132+
List<String> paths = CollectionUtils.isEmpty(this.nestedPaths.get(this.level)) ? new ArrayList<>() : this.nestedPaths.get(this.level);
133+
paths.add(pattern);
134+
this.nestedPaths.put(this.level, paths);
135+
}
107136
}
108137

109138
/**
@@ -113,14 +142,12 @@ else if (isNested)
113142
* @param value the value
114143
*/
115144
public void header(String name, String value) {
116-
if (HttpHeaders.ACCEPT.equals(name)) {
117-
calculateAccept(value);
118-
}
119-
else if (HttpHeaders.CONTENT_TYPE.equals(name)) {
120-
calculateContentType(value);
121-
}
145+
if (HttpHeaders.ACCEPT.equals(name))
146+
calculateHeader(value, this.produces, name);
147+
else if (HttpHeaders.CONTENT_TYPE.equals(name))
148+
calculateHeader(value, this.consumes, name);
122149
else
123-
routerFunctionData.addHeaders(name + "=" + value);
150+
currentRouterFunctionDatas.forEach(routerFunctionData -> routerFunctionData.addHeaders(name + "=" + value));
124151
}
125152

126153
/**
@@ -139,7 +166,10 @@ public List<RouterFunctionData> getRouterFunctionDatas() {
139166
* @param value the value
140167
*/
141168
public void queryParam(String name, String value) {
142-
routerFunctionData.addQueryParams(name, value);
169+
if (CollectionUtils.isEmpty(currentRouterFunctionDatas))
170+
queryParams.put(name, value);
171+
else
172+
currentRouterFunctionDatas.forEach(routerFunctionData -> routerFunctionData.addQueryParams(name, value));
143173
}
144174

145175
/**
@@ -200,7 +230,7 @@ public void or() {
200230
* End or.
201231
*/
202232
public void endOr() {
203-
// Not yet needed
233+
this.isOr = false;
204234
}
205235

206236
/**
@@ -217,96 +247,90 @@ public void endNegate() {
217247
// Not yet needed
218248
}
219249

250+
/**
251+
* Attributes.
252+
*
253+
* @param map the map
254+
*/
255+
public void attributes(Map<String, Object> map) {
256+
this.attributes = map;
257+
}
258+
220259
/**
221260
* Compute nested.
222261
*/
223-
protected void computeNested() {
224-
if (!nestedAndPaths.isEmpty()) {
225-
String nestedPath = String.join(StringUtils.EMPTY, nestedAndPaths);
226-
routerFunctionDatas.forEach(existingRouterFunctionData -> existingRouterFunctionData.setPath(nestedPath + existingRouterFunctionData.getPath()));
227-
nestedAndPaths.clear();
228-
}
229-
if (!nestedOrPaths.isEmpty()) {
230-
List<RouterFunctionData> routerFunctionDatasClone = new ArrayList<>();
231-
for (RouterFunctionData functionData : routerFunctionDatas) {
232-
for (String nestedOrPath : nestedOrPaths) {
233-
RouterFunctionData routerFunctionDataClone = new RouterFunctionData(nestedOrPath , functionData);
234-
routerFunctionDatasClone.add(routerFunctionDataClone);
235-
}
236-
}
237-
this.routerFunctionDatas = routerFunctionDatasClone;
238-
nestedAndPaths.clear();
239-
}
240-
if (!nestedAcceptHeaders.isEmpty()) {
241-
routerFunctionDatas.forEach(existingRouterFunctionData -> existingRouterFunctionData.addProduces(nestedAcceptHeaders));
242-
nestedAcceptHeaders.clear();
243-
}
244-
if (!nestedContentTypeHeaders.isEmpty()) {
245-
routerFunctionDatas.forEach(existingRouterFunctionData -> existingRouterFunctionData.addConsumes(nestedContentTypeHeaders));
246-
nestedContentTypeHeaders.clear();
247-
}
262+
protected void commonEndNested() {
263+
nestedPaths.remove(this.level);
264+
this.level--;
248265
}
249266

250267
/**
251-
* Calculate content type.
252-
*
253-
* @param value the value
268+
* Common start nested.
254269
*/
255-
private void calculateContentType(String value) {
256-
if (value.contains(",")) {
257-
String[] mediaTypes = value.substring(1, value.length() - 1).split(", ");
258-
for (String mediaType : mediaTypes)
259-
if (routerFunctionData != null)
260-
routerFunctionData.addConsumes(mediaType);
261-
else
262-
nestedContentTypeHeaders.addAll(Arrays.asList(mediaTypes));
263-
}
264-
else {
265-
if (routerFunctionData != null)
266-
routerFunctionData.addConsumes(value);
267-
else
268-
nestedContentTypeHeaders.add(value);
269-
}
270+
protected void commonStartNested() {
271+
this.level++;
272+
this.currentRouterFunctionDatas = null;
273+
}
274+
275+
/**
276+
* Common route.
277+
*/
278+
protected void commonRoute() {
279+
this.routerFunctionDatas.addAll(currentRouterFunctionDatas);
280+
currentRouterFunctionDatas.forEach(routerFunctionData -> routerFunctionData.addAttributes(this.attributes));
281+
this.attributes = new HashMap<>();
270282
}
271283

272284
/**
273-
* Calculate accept.
285+
* Calculate header.
274286
*
275287
* @param value the value
288+
* @param headers the headers
289+
* @param header the header
276290
*/
277-
private void calculateAccept(String value) {
291+
private void calculateHeader(String value, List<String> headers, String header) {
278292
if (value.contains(",")) {
279293
String[] mediaTypes = value.substring(1, value.length() - 1).split(", ");
280294
for (String mediaType : mediaTypes)
281-
if (routerFunctionData != null)
282-
routerFunctionData.addProduces(mediaType);
295+
if (CollectionUtils.isEmpty(currentRouterFunctionDatas))
296+
headers.add(mediaType);
283297
else
284-
nestedAcceptHeaders.addAll(Arrays.asList(mediaTypes));
298+
currentRouterFunctionDatas.forEach(routerFunctionData -> addHeader(mediaType, header, routerFunctionData));
285299
}
286300
else {
287-
if (routerFunctionData != null)
288-
routerFunctionData.addProduces(value);
301+
if (CollectionUtils.isEmpty(currentRouterFunctionDatas))
302+
headers.add(value);
289303
else
290-
nestedAcceptHeaders.add(value);
304+
currentRouterFunctionDatas.forEach(routerFunctionData -> addHeader(value, header, routerFunctionData));
291305
}
292306
}
293307

294308
/**
295-
* Route.
309+
* Create router function data.
310+
*
311+
* @param path the path
296312
*/
297-
protected void route() {
298-
this.routerFunctionData = new RouterFunctionData();
299-
routerFunctionDatas.add(this.routerFunctionData);
300-
this.routerFunctionData.addAttributes(this.attributes);
313+
private void createRouterFunctionData(String path) {
314+
RouterFunctionData routerFunctionData = new RouterFunctionData();
315+
routerFunctionData.setPath(path);
316+
routerFunctionData.setMethods(methods);
317+
routerFunctionData.addConsumes(consumes);
318+
routerFunctionData.addProduces(produces);
319+
this.queryParams.forEach(routerFunctionData::addQueryParams);
320+
this.currentRouterFunctionDatas.add(routerFunctionData);
301321
}
302322

303323
/**
304-
* Attributes.
324+
* Add header.
305325
*
306-
* @param map the map
326+
* @param mediaType the media type
327+
* @param header the header
328+
* @param routerFunctionData the router function data
307329
*/
308-
public void attributes(Map<String, Object> map) {
309-
this.attributes = map;
330+
private void addHeader(String mediaType, String header,RouterFunctionData routerFunctionData) {
331+
if (HttpHeaders.CONTENT_TYPE.equals(header))
332+
routerFunctionData.addConsumes(mediaType);
333+
else if (HttpHeaders.ACCEPT.equals(header))
334+
routerFunctionData.addProduces(mediaType);
310335
}
311-
312336
}

springdoc-openapi-webflux-core/src/main/java/org/springdoc/webflux/core/visitor/RouterFunctionVisitor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
package org.springdoc.webflux.core.visitor;
2222

23-
import java.util.HashMap;
23+
import java.util.ArrayList;
2424
import java.util.function.Function;
2525

2626
import org.springdoc.core.fn.AbstractRouterFunctionVisitor;
@@ -42,20 +42,20 @@ public class RouterFunctionVisitor extends AbstractRouterFunctionVisitor impleme
4242

4343
@Override
4444
public void route(RequestPredicate predicate, HandlerFunction<?> handlerFunction) {
45-
super.route();
45+
this.currentRouterFunctionDatas = new ArrayList<>();
4646
predicate.accept(this);
47-
this.attributes = new HashMap<>();
47+
commonRoute();
4848
}
4949

5050
@Override
5151
public void startNested(RequestPredicate predicate) {
52-
this.isNested = true;
52+
commonStartNested();
5353
predicate.accept(this);
5454
}
5555

5656
@Override
5757
public void endNested(RequestPredicate predicate) {
58-
computeNested();
58+
commonEndNested();
5959
}
6060

6161
@Override

0 commit comments

Comments
 (0)