Skip to content

Commit 0346b6a

Browse files
author
bnasslahsen
committed
Add options to filter on the GroupedOpenApi by consumes/produces mediaTypes or by header. Fixes #878,#449.
1 parent d6e216e commit 0346b6a

File tree

15 files changed

+1038
-70
lines changed

15 files changed

+1038
-70
lines changed

springdoc-openapi-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java

+97-3
Original file line numberDiff line numberDiff line change
@@ -434,14 +434,14 @@ protected void calculatePath(List<RouterOperation> routerOperationList) {
434434
catch (NoSuchMethodException e) {
435435
LOGGER.error(e.getMessage());
436436
}
437-
if (handlerMethod != null && isPackageToScan(handlerMethod.getBeanType().getPackage()) && isPathToMatch(routerOperation.getPath()))
437+
if (handlerMethod != null && isFilterCondition(handlerMethod, routerOperation.getPath(), routerOperation.getProduces(), routerOperation.getConsumes(), routerOperation.getHeaders()))
438438
calculatePath(handlerMethod, routerOperation);
439439
}
440440
}
441-
else if (routerOperation.getOperation() != null && StringUtils.isNotBlank(routerOperation.getOperation().operationId()) && isPathToMatch(routerOperation.getPath())) {
441+
else if (routerOperation.getOperation() != null && StringUtils.isNotBlank(routerOperation.getOperation().operationId()) && isFilterCondition(routerOperation.getPath(), routerOperation.getProduces(), routerOperation.getConsumes(), routerOperation.getHeaders())) {
442442
calculatePath(routerOperation);
443443
}
444-
else if (routerOperation.getOperationModel() != null && StringUtils.isNotBlank(routerOperation.getOperationModel().getOperationId()) && isPathToMatch(routerOperation.getPath())) {
444+
else if (routerOperation.getOperationModel() != null && StringUtils.isNotBlank(routerOperation.getOperationModel().getOperationId()) && isFilterCondition(routerOperation.getPath(), routerOperation.getProduces(), routerOperation.getConsumes(), routerOperation.getHeaders())) {
445445
calculatePath(routerOperation);
446446
}
447447
}
@@ -531,6 +531,39 @@ protected void getRouterFunctionPaths(String beanName, AbstractRouterFunctionVis
531531
}
532532
}
533533

534+
/**
535+
* Is filter condition boolean.
536+
*
537+
* @param handlerMethod the handler method
538+
* @param operationPath the operation path
539+
* @param produces the produces
540+
* @param consumes the consumes
541+
* @param headers the headers
542+
* @return the boolean
543+
*/
544+
protected boolean isFilterCondition(HandlerMethod handlerMethod, String operationPath, String[] produces, String[] consumes, String[] headers) {
545+
return isPackageToScan(handlerMethod.getBeanType().getPackage())
546+
&& isFilterCondition(operationPath, produces, consumes, headers);
547+
}
548+
549+
/**
550+
* Is condition to match boolean.
551+
*
552+
* @param existingConditions the existing conditions
553+
* @param conditionType the condition type
554+
* @return the boolean
555+
*/
556+
protected boolean isConditionToMatch(String[] existingConditions, ConditionType conditionType) {
557+
List<String> conditionsToMatch = getConditionsToMatch(conditionType);
558+
if (CollectionUtils.isEmpty(conditionsToMatch)) {
559+
Optional<GroupConfig> optionalGroupConfig = springDocConfigProperties.getGroupConfigs().stream().filter(groupConfig -> this.groupName.equals(groupConfig.getGroup())).findAny();
560+
if (optionalGroupConfig.isPresent())
561+
conditionsToMatch = getConditionsToMatch(conditionType, optionalGroupConfig.get());
562+
}
563+
return CollectionUtils.isEmpty(conditionsToMatch)
564+
|| (!ArrayUtils.isEmpty(existingConditions) && conditionsToMatch.size() == existingConditions.length && conditionsToMatch.containsAll(Arrays.asList(existingConditions)));
565+
}
566+
534567
/**
535568
* Is package to scan boolean.
536569
*
@@ -972,4 +1005,65 @@ protected ObjectMapper getYamlMapper() {
9721005
factory.configure(Feature.USE_NATIVE_TYPE_ID, false);
9731006
return objectMapper;
9741007
}
1008+
1009+
/**
1010+
* Gets conditions to match.
1011+
*
1012+
* @param conditionType the condition type
1013+
* @param groupConfigs the group configs
1014+
* @return the conditions to match
1015+
*/
1016+
private List<String> getConditionsToMatch(ConditionType conditionType, GroupConfig... groupConfigs) {
1017+
List<String> conditionsToMatch = null;
1018+
GroupConfig groupConfig = null;
1019+
if (ArrayUtils.isNotEmpty(groupConfigs))
1020+
groupConfig = groupConfigs[0];
1021+
switch (conditionType) {
1022+
case HEADERS:
1023+
conditionsToMatch = (groupConfig != null) ? groupConfig.getHeadersToMatch() : springDocConfigProperties.getHeadersToMatch();
1024+
break;
1025+
case PRODUCES:
1026+
conditionsToMatch = (groupConfig != null) ? groupConfig.getProducesToMatch() : springDocConfigProperties.getProducesToMatch();
1027+
break;
1028+
case CONSUMES:
1029+
conditionsToMatch = (groupConfig != null) ? groupConfig.getConsumesToMatch(): springDocConfigProperties.getConsumesToMatch();
1030+
break;
1031+
default:
1032+
break;
1033+
} return conditionsToMatch;
1034+
}
1035+
1036+
/**
1037+
* Is filter condition boolean.
1038+
*
1039+
* @param operationPath the operation path
1040+
* @param produces the produces
1041+
* @param consumes the consumes
1042+
* @param headers the headers
1043+
* @return the boolean
1044+
*/
1045+
private boolean isFilterCondition(String operationPath, String[] produces, String[] consumes, String[] headers) {
1046+
return isPathToMatch(operationPath)
1047+
&& isConditionToMatch(produces, ConditionType.PRODUCES)
1048+
&& isConditionToMatch(consumes, ConditionType.CONSUMES)
1049+
&& isConditionToMatch(headers, ConditionType.HEADERS);
1050+
}
1051+
1052+
/**
1053+
* The enum Condition type.
1054+
*/
1055+
enum ConditionType {
1056+
/**
1057+
*Produces condition type.
1058+
*/
1059+
PRODUCES,
1060+
/**
1061+
*Consumes condition type.
1062+
*/
1063+
CONSUMES,
1064+
/**
1065+
*Headers condition type.
1066+
*/
1067+
HEADERS
1068+
}
9751069
}

springdoc-openapi-common/src/main/java/org/springdoc/core/GroupedOpenApi.java

+43
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ public class GroupedOpenApi {
7373
*/
7474
private final List<String> pathsToExclude;
7575

76+
private final List<String> producesToMatch;
77+
78+
private final List<String> headersToMatch;
79+
80+
private final List<String> consumesToMatch;
81+
7682
/**
7783
* Instantiates a new Grouped open api.
7884
*
@@ -82,12 +88,18 @@ private GroupedOpenApi(Builder builder) {
8288
this.group = Objects.requireNonNull(builder.group, GROUP_NAME_NOT_NULL);
8389
this.pathsToMatch = builder.pathsToMatch;
8490
this.packagesToScan = builder.packagesToScan;
91+
this.producesToMatch = builder.producesToMatch;
92+
this.consumesToMatch = builder.consumesToMatch;
93+
this.headersToMatch = builder.headersToMatch;
8594
this.packagesToExclude = builder.packagesToExclude;
8695
this.pathsToExclude = builder.pathsToExclude;
8796
this.openApiCustomisers = Objects.requireNonNull(builder.openApiCustomisers);
8897
this.operationCustomizers = Objects.requireNonNull(builder.operationCustomizers);
8998
if (CollectionUtils.isEmpty(this.pathsToMatch)
9099
&& CollectionUtils.isEmpty(this.packagesToScan)
100+
&& CollectionUtils.isEmpty(this.producesToMatch)
101+
&& CollectionUtils.isEmpty(this.consumesToMatch)
102+
&& CollectionUtils.isEmpty(this.headersToMatch)
91103
&& CollectionUtils.isEmpty(this.pathsToExclude)
92104
&& CollectionUtils.isEmpty(this.packagesToExclude)
93105
&& CollectionUtils.isEmpty(openApiCustomisers)
@@ -104,6 +116,18 @@ public static Builder builder() {
104116
return new Builder();
105117
}
106118

119+
public List<String> getProducesToMatch() {
120+
return producesToMatch;
121+
}
122+
123+
public List<String> getHeadersToMatch() {
124+
return headersToMatch;
125+
}
126+
127+
public List<String> getConsumesToMatch() {
128+
return consumesToMatch;
129+
}
130+
107131
/**
108132
* Gets group.
109133
*
@@ -207,6 +231,12 @@ public static class Builder {
207231
*/
208232
private List<String> pathsToExclude;
209233

234+
private List<String> producesToMatch;
235+
236+
private List<String> headersToMatch;
237+
238+
private List<String> consumesToMatch;
239+
210240
/**
211241
* Instantiates a new Builder.
212242
*/
@@ -260,6 +290,19 @@ public Builder packagesToScan(String... packagesToScan) {
260290
return this;
261291
}
262292

293+
public Builder producesToMatch(String... producesToMatch) {
294+
this.producesToMatch = Arrays.asList(producesToMatch);
295+
return this;
296+
}
297+
298+
public Builder consumesToMatch(String... consumesToMatch) {
299+
this.consumesToMatch = Arrays.asList(consumesToMatch);
300+
return this;
301+
}
302+
public Builder headersToMatch(String... headersToMatch) {
303+
this.headersToMatch = Arrays.asList(headersToMatch);
304+
return this;
305+
}
263306
/**
264307
* Paths to exclude builder.
265308
*

springdoc-openapi-common/src/main/java/org/springdoc/core/SpringDocConfigProperties.java

+148-1
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,21 @@ public class SpringDocConfigProperties {
7777
*/
7878
private List<String> pathsToExclude;
7979

80+
/**
81+
* The Produces to match.
82+
*/
83+
private List<String> producesToMatch;
84+
85+
/**
86+
* The Headers to match.
87+
*/
88+
private List<String> headersToMatch;
89+
90+
/**
91+
* The Consumes to match.
92+
*/
93+
private List<String> consumesToMatch;
94+
8095
/**
8196
* The Cache.
8297
*/
@@ -137,6 +152,61 @@ public class SpringDocConfigProperties {
137152
*/
138153
private boolean preLoadingEnabled;
139154

155+
156+
/**
157+
* Gets produces to match.
158+
*
159+
* @return the produces to match
160+
*/
161+
public List<String> getProducesToMatch() {
162+
return producesToMatch;
163+
}
164+
165+
/**
166+
* Sets produces to match.
167+
*
168+
* @param producesToMatch the produces to match
169+
*/
170+
public void setProducesToMatch(List<String> producesToMatch) {
171+
this.producesToMatch = producesToMatch;
172+
}
173+
174+
/**
175+
* Gets headers to match.
176+
*
177+
* @return the headers to match
178+
*/
179+
public List<String> getHeadersToMatch() {
180+
return headersToMatch;
181+
}
182+
183+
/**
184+
* Sets headers to match.
185+
*
186+
* @param headersToMatch the headers to match
187+
*/
188+
public void setHeadersToMatch(List<String> headersToMatch) {
189+
this.headersToMatch = headersToMatch;
190+
}
191+
192+
/**
193+
* Gets consumes to match.
194+
*
195+
* @return the consumes to match
196+
*/
197+
public List<String> getConsumesToMatch() {
198+
return consumesToMatch;
199+
}
200+
201+
/**
202+
* Sets consumes to match.
203+
*
204+
* @param consumesToMatch the consumes to match
205+
*/
206+
public void setConsumesToMatch(List<String> consumesToMatch) {
207+
this.consumesToMatch = consumesToMatch;
208+
}
209+
140210
/**
141211
* Is use fqn boolean.
142212
*
@@ -772,6 +842,21 @@ public static class GroupConfig {
772842
*/
773843
private String group;
774844

845+
/**
846+
* The Produces to match.
847+
*/
848+
private List<String> producesToMatch;
849+
850+
/**
851+
* The Headers to match.
852+
*/
853+
private List<String> headersToMatch;
854+
855+
/**
856+
* The Consumes to match.
857+
*/
858+
private List<String> consumesToMatch;
859+
775860
/**
776861
* Instantiates a new Group config.
777862
*/
@@ -786,13 +871,57 @@ public GroupConfig() {
786871
* @param packagesToScan the packages to scan
787872
* @param packagesToExclude the packages to exclude
788873
* @param pathsToExclude the paths to exclude
874+
* @param producesToMatch the produces to match
875+
* @param consumesToMatch the consumes to match
876+
* @param headersToMatch the headers to match
789877
*/
790-
public GroupConfig(String group, List<String> pathsToMatch, List<String> packagesToScan, List<String> packagesToExclude, List<String> pathsToExclude) {
878+
public GroupConfig(String group, List<String> pathsToMatch, List<String> packagesToScan,
879+
List<String> packagesToExclude, List<String> pathsToExclude,
880+
List<String> producesToMatch,List<String> consumesToMatch,List<String> headersToMatch) {
791881
this.pathsToMatch = pathsToMatch;
792882
this.pathsToExclude = pathsToExclude;
793883
this.packagesToExclude = packagesToExclude;
794884
this.packagesToScan = packagesToScan;
795885
this.group = group;
886+
this.producesToMatch = producesToMatch;
887+
this.consumesToMatch = consumesToMatch;
888+
this.headersToMatch = headersToMatch;
889+
}
890+
891+
/**
892+
* Gets headers to match.
893+
*
894+
* @return the headers to match
895+
*/
896+
public List<String> getHeadersToMatch() {
897+
return headersToMatch;
898+
}
899+
900+
/**
901+
* Sets headers to match.
902+
*
903+
* @param headersToMatch the headers to match
904+
*/
905+
public void setHeadersToMatch(List<String> headersToMatch) {
906+
this.headersToMatch = headersToMatch;
907+
}
908+
909+
/**
910+
* Gets consumes to match.
911+
*
912+
* @return the consumes to match
913+
*/
914+
public List<String> getConsumesToMatch() {
915+
return consumesToMatch;
916+
}
917+
918+
/**
919+
* Sets consumes to match.
920+
*
921+
* @param consumesToMatch the consumes to match
922+
*/
923+
public void setConsumesToMatch(List<String> consumesToMatch) {
924+
this.consumesToMatch = consumesToMatch;
796925
}
797926

798927
/**
@@ -884,5 +1013,23 @@ public List<String> getPathsToExclude() {
8841013
public void setPathsToExclude(List<String> pathsToExclude) {
8851014
this.pathsToExclude = pathsToExclude;
8861015
}
1016+
1017+
/**
1018+
* Gets produces to match.
1019+
*
1020+
* @return the produces to match
1021+
*/
1022+
public List<String> getProducesToMatch() {
1023+
return producesToMatch;
1024+
}
1025+
1026+
/**
1027+
* Sets produces to match.
1028+
*
1029+
* @param producesToMatch the produces to match
1030+
*/
1031+
public void setProducesToMatch(List<String> producesToMatch) {
1032+
this.producesToMatch = producesToMatch;
1033+
}
8871034
}
8881035
}

0 commit comments

Comments
 (0)