Skip to content

Commit a7f685f

Browse files
committed
OperationCustomizer is not working with Spring Data REST. #2062
1 parent 0a1b200 commit a7f685f

File tree

22 files changed

+440
-361
lines changed

22 files changed

+440
-361
lines changed

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

+46-63
Original file line numberDiff line numberDiff line change
@@ -75,11 +75,10 @@
7575
import org.slf4j.Logger;
7676
import org.slf4j.LoggerFactory;
7777
import org.springdoc.core.annotations.RouterOperations;
78-
import org.springdoc.core.customizers.OpenApiCustomizer;
79-
import org.springdoc.core.customizers.OpenApiLocaleCustomizer;
78+
import org.springdoc.core.customizers.DataRestRouterOperationCustomizer;
8079
import org.springdoc.core.customizers.OperationCustomizer;
8180
import org.springdoc.core.customizers.RouterOperationCustomizer;
82-
import org.springdoc.core.filters.OpenApiMethodFilter;
81+
import org.springdoc.core.customizers.SpringDocCustomizers;
8382
import org.springdoc.core.fn.AbstractRouterFunctionVisitor;
8483
import org.springdoc.core.fn.RouterFunctionData;
8584
import org.springdoc.core.fn.RouterOperation;
@@ -115,13 +114,13 @@
115114
import static org.springdoc.core.converters.SchemaPropertyDeprecatingConverter.isDeprecated;
116115
import static org.springdoc.core.utils.Constants.ACTUATOR_DEFAULT_GROUP;
117116
import static org.springdoc.core.utils.Constants.DOT;
118-
import static org.springdoc.core.utils.Constants.LINKS_SCHEMA_CUSTOMISER;
119117
import static org.springdoc.core.utils.Constants.OPERATION_ATTRIBUTE;
120118
import static org.springdoc.core.utils.Constants.SPRING_MVC_SERVLET_PATH;
121119
import static org.springframework.util.AntPathMatcher.DEFAULT_PATH_SEPARATOR;
122120

123121
/**
124122
* The type Abstract open api resource.
123+
*
125124
* @author bnasslahsen
126125
* @author kevinraddatz
127126
* @author hyeonisism
@@ -184,84 +183,46 @@ public abstract class AbstractOpenApiResource extends SpecFilter {
184183
*/
185184
private final OperationService operationParser;
186185

187-
/**
188-
* The Open api customisers.
189-
*/
190-
private final Optional<List<OpenApiCustomizer>> openApiCustomizers;
191-
192-
/**
193-
* The Operation customizers.
194-
*/
195-
private final Optional<List<OperationCustomizer>> operationCustomizers;
196-
197-
/**
198-
* The RouterOperation customizers.
199-
*/
200-
private final Optional<List<RouterOperationCustomizer>> routerOperationCustomizers;
201-
202-
/**
203-
* The method filters to use.
204-
*/
205-
private final Optional<List<OpenApiMethodFilter>> methodFilters;
206-
207186
/**
208187
* The Ant path matcher.
209188
*/
210189
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
211190

212-
/**
213-
* The OpenApi with locale customizers.
214-
*/
215-
private final Map<String, OpenApiLocaleCustomizer> openApiLocaleCustomizers;
216-
217191
/**
218192
* The Open api builder.
219193
*/
220194
protected OpenAPIService openAPIService;
221195

196+
protected final SpringDocCustomizers springDocCustomizers;
197+
222198
/**
223199
* Instantiates a new Abstract open api resource.
200+
*
224201
* @param groupName the group name
225202
* @param openAPIBuilderObjectFactory the open api builder object factory
226203
* @param requestBuilder the request builder
227204
* @param responseBuilder the response builder
228205
* @param operationParser the operation parser
229-
* @param operationCustomizers the operation customizers
230-
* @param openApiCustomizers the open api customisers
231-
* @param routerOperationCustomizers the router operation customisers
232-
* @param methodFilters the method filters
233206
* @param springDocConfigProperties the spring doc config properties
234207
* @param springDocProviders the spring doc providers
208+
* @param springDocCustomizers the spring doc customizers
235209
*/
236210
protected AbstractOpenApiResource(String groupName, ObjectFactory<OpenAPIService> openAPIBuilderObjectFactory,
237211
AbstractRequestService requestBuilder,
238212
GenericResponseService responseBuilder, OperationService operationParser,
239-
Optional<List<OperationCustomizer>> operationCustomizers,
240-
Optional<List<OpenApiCustomizer>> openApiCustomizers,
241-
Optional<List<RouterOperationCustomizer>> routerOperationCustomizers,
242-
Optional<List<OpenApiMethodFilter>> methodFilters,
243-
SpringDocConfigProperties springDocConfigProperties, SpringDocProviders springDocProviders) {
213+
SpringDocConfigProperties springDocConfigProperties, SpringDocProviders springDocProviders, SpringDocCustomizers springDocCustomizers) {
244214
super();
245215
this.groupName = Objects.requireNonNull(groupName, "groupName");
246216
this.openAPIBuilderObjectFactory = openAPIBuilderObjectFactory;
247217
this.openAPIService = openAPIBuilderObjectFactory.getObject();
248218
this.requestBuilder = requestBuilder;
249219
this.responseBuilder = responseBuilder;
250220
this.operationParser = operationParser;
251-
this.openApiCustomizers = openApiCustomizers;
252-
this.routerOperationCustomizers = routerOperationCustomizers;
253-
this.methodFilters = methodFilters;
254221
this.springDocProviders = springDocProviders;
255-
//add the default customizers
256-
Map<String, OpenApiCustomizer> existingOpenApiCustomizers = openAPIService.getContext().getBeansOfType(OpenApiCustomizer.class);
257-
if (!CollectionUtils.isEmpty(existingOpenApiCustomizers) && existingOpenApiCustomizers.containsKey(LINKS_SCHEMA_CUSTOMISER))
258-
openApiCustomizers.ifPresent(openApiCustomizersList -> openApiCustomizersList.add(existingOpenApiCustomizers.get(LINKS_SCHEMA_CUSTOMISER)));
222+
this.springDocCustomizers = springDocCustomizers;
259223
this.springDocConfigProperties = springDocConfigProperties;
260-
operationCustomizers.ifPresent(customizers -> customizers.removeIf(Objects::isNull));
261-
this.operationCustomizers = operationCustomizers;
262224
if (springDocConfigProperties.isPreLoadingEnabled())
263225
Executors.newSingleThreadExecutor().execute(this::getOpenApi);
264-
this.openApiLocaleCustomizers = openAPIService.getContext().getBeansOfType(OpenApiLocaleCustomizer.class);
265226
}
266227

267228
/**
@@ -341,6 +302,7 @@ private void getOpenApi() {
341302

342303
/**
343304
* Gets open api.
305+
*
344306
* @param locale the locale
345307
* @return the open api
346308
*/
@@ -391,8 +353,8 @@ protected synchronized OpenAPI getOpenApi(Locale locale) {
391353
LOGGER.warn("Json Processing Exception occurred: {}", e.getMessage());
392354
}
393355

394-
openApiLocaleCustomizers.values().forEach(openApiLocaleCustomizer -> openApiLocaleCustomizer.customise(openAPI, finalLocale));
395-
openApiCustomizers.ifPresent(apiCustomizers -> apiCustomizers.forEach(openApiCustomizer -> openApiCustomizer.customise(openAPI)));
356+
springDocCustomizers.getOpenApiLocaleCustomizers().values().forEach(openApiLocaleCustomizer -> openApiLocaleCustomizer.customise(openAPI, finalLocale));
357+
springDocCustomizers.getOpenApiCustomizers().ifPresent(apiCustomizers -> apiCustomizers.forEach(openApiCustomizer -> openApiCustomizer.customise(openAPI)));
396358
if (!CollectionUtils.isEmpty(openAPI.getServers()) && !openAPI.getServers().equals(serversCopy))
397359
openAPIService.setServersPresent(true);
398360

@@ -609,6 +571,8 @@ else if (routerOperation.getOperationModel() != null && StringUtils.isNotBlank(r
609571
* @param locale the locale
610572
*/
611573
protected void calculatePath(RouterOperation routerOperation, Locale locale, OpenAPI openAPI) {
574+
routerOperation = customizeDataRestRouterOperation(routerOperation);
575+
612576
String operationPath = routerOperation.getPath();
613577
io.swagger.v3.oas.annotations.Operation apiOperation = routerOperation.getOperation();
614578
String[] methodConsumes = routerOperation.getConsumes();
@@ -644,11 +608,28 @@ protected void calculatePath(RouterOperation routerOperation, Locale locale, Ope
644608
parameter.setIn(ParameterIn.QUERY.toString());
645609
}
646610
);
611+
647612
PathItem pathItemObject = buildPathItem(requestMethod, operation, operationPath, paths);
648613
paths.addPathItem(operationPath, pathItemObject);
649614
}
650615
}
651616

617+
/**
618+
* Customize data rest router operation router operation.
619+
*
620+
* @param routerOperation the router operation
621+
* @return the router operation
622+
*/
623+
private RouterOperation customizeDataRestRouterOperation(RouterOperation routerOperation) {
624+
if (springDocCustomizers.getDataRestRouterOperationCustomizers().isPresent()) {
625+
List<DataRestRouterOperationCustomizer> dataRestRouterOperationCustomizerList = springDocCustomizers.getDataRestRouterOperationCustomizers().get();
626+
for (DataRestRouterOperationCustomizer dataRestRouterOperationCustomizer : dataRestRouterOperationCustomizerList) {
627+
routerOperation = dataRestRouterOperationCustomizer.customize(routerOperation);
628+
}
629+
}
630+
return routerOperation;
631+
}
632+
652633
/**
653634
* Calculate path.
654635
*
@@ -725,7 +706,7 @@ && isPackageToScan(handlerMethod.getBeanType().getPackage())
725706
* @return whether the method should be included in the current OpenAPI definition
726707
*/
727708
protected boolean isMethodToFilter(HandlerMethod handlerMethod) {
728-
return this.methodFilters
709+
return this.springDocCustomizers.getMethodFilters()
729710
.map(Collection::stream)
730711
.map(stream -> stream.allMatch(m -> m.isMethodToInclude(handlerMethod.getMethod())))
731712
.orElse(true);
@@ -865,8 +846,8 @@ protected Set<RequestMethod> getDefaultAllowedHttpMethods() {
865846
* @return the operation
866847
*/
867848
protected Operation customiseOperation(Operation operation, HandlerMethod handlerMethod) {
868-
if (operationCustomizers.isPresent()) {
869-
List<OperationCustomizer> operationCustomizerList = operationCustomizers.get();
849+
if (springDocCustomizers.getOperationCustomizers().isPresent()) {
850+
List<OperationCustomizer> operationCustomizerList = springDocCustomizers.getOperationCustomizers().get();
870851
for (OperationCustomizer operationCustomizer : operationCustomizerList)
871852
operation = operationCustomizer.customize(operation, handlerMethod);
872853
}
@@ -875,13 +856,14 @@ protected Operation customiseOperation(Operation operation, HandlerMethod handle
875856

876857
/**
877858
* Customise router operation
859+
*
878860
* @param routerOperation
879861
* @param handlerMethod
880862
* @return the router operation
881863
*/
882864
protected RouterOperation customizeRouterOperation(RouterOperation routerOperation, HandlerMethod handlerMethod) {
883-
if (routerOperationCustomizers.isPresent()) {
884-
List<RouterOperationCustomizer> routerOperationCustomizerList = routerOperationCustomizers.get();
865+
if (springDocCustomizers.getRouterOperationCustomizers().isPresent()) {
866+
List<RouterOperationCustomizer> routerOperationCustomizerList = springDocCustomizers.getRouterOperationCustomizers().get();
885867
for (RouterOperationCustomizer routerOperationCustomizer : routerOperationCustomizerList) {
886868
routerOperation = routerOperationCustomizer.customize(routerOperation, handlerMethod);
887869
}
@@ -1050,7 +1032,7 @@ private void fillParametersList(Operation operation, Map<String, String> queryPa
10501032
Collection<Parameter> headersMap = AbstractRequestService.getHeaders(methodAttributes, new LinkedHashMap<>());
10511033
headersMap.forEach(parameter -> {
10521034
Optional<Parameter> existingParam;
1053-
if (!CollectionUtils.isEmpty(operation.getParameters())){
1035+
if (!CollectionUtils.isEmpty(operation.getParameters())) {
10541036
existingParam = operation.getParameters().stream().filter(p -> parameter.getName().equals(p.getName())).findAny();
10551037
if (existingParam.isEmpty())
10561038
operation.addParametersItem(parameter);
@@ -1100,13 +1082,13 @@ private void fillRouterOperation(RouterFunctionData routerFunctionData, RouterOp
11001082
private PathItem buildPathItem(RequestMethod requestMethod, Operation operation, String operationPath,
11011083
Paths paths) {
11021084
PathItem pathItemObject;
1103-
if(operation!=null && !CollectionUtils.isEmpty(operation.getParameters())){
1085+
if (operation != null && !CollectionUtils.isEmpty(operation.getParameters())) {
11041086
Iterator<Parameter> paramIt = operation.getParameters().iterator();
1105-
while (paramIt.hasNext()){
1087+
while (paramIt.hasNext()) {
11061088
Parameter parameter = paramIt.next();
1107-
if(ParameterIn.PATH.toString().equals(parameter.getIn())){
1089+
if (ParameterIn.PATH.toString().equals(parameter.getIn())) {
11081090
// check it's present in the path
1109-
if(!operationPath.contains("{" + parameter.getName() + "}"))
1091+
if (!operationPath.contains("{" + parameter.getName() + "}"))
11101092
paramIt.remove();
11111093
}
11121094
}
@@ -1216,6 +1198,7 @@ else if (existingOperation != null) {
12161198

12171199
/**
12181200
* Init open api builder.
1201+
*
12191202
* @param locale the locale
12201203
*/
12211204
protected void initOpenAPIBuilder(Locale locale) {
@@ -1364,15 +1347,15 @@ && isConditionToMatch(consumes, ConditionType.CONSUMES)
13641347
*/
13651348
enum ConditionType {
13661349
/**
1367-
*Produces condition type.
1350+
* Produces condition type.
13681351
*/
13691352
PRODUCES,
13701353
/**
1371-
*Consumes condition type.
1354+
* Consumes condition type.
13721355
*/
13731356
CONSUMES,
13741357
/**
1375-
*Headers condition type.
1358+
* Headers condition type.
13761359
*/
13771360
HEADERS
13781361
}

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/configuration/SpringDocConfiguration.java

+31
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,19 @@
5555
import org.springdoc.core.converters.WebFluxSupportConverter;
5656
import org.springdoc.core.customizers.ActuatorOpenApiCustomizer;
5757
import org.springdoc.core.customizers.ActuatorOperationCustomizer;
58+
import org.springdoc.core.customizers.DataRestRouterOperationCustomizer;
5859
import org.springdoc.core.customizers.DelegatingMethodParameterCustomizer;
5960
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
6061
import org.springdoc.core.customizers.GlobalOperationCustomizer;
6162
import org.springdoc.core.customizers.OpenApiBuilderCustomizer;
63+
import org.springdoc.core.customizers.OpenApiCustomizer;
64+
import org.springdoc.core.customizers.OperationCustomizer;
6265
import org.springdoc.core.customizers.PropertyCustomizer;
66+
import org.springdoc.core.customizers.RouterOperationCustomizer;
6367
import org.springdoc.core.customizers.ServerBaseUrlCustomizer;
68+
import org.springdoc.core.customizers.SpringDocCustomizers;
6469
import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer;
70+
import org.springdoc.core.filters.OpenApiMethodFilter;
6571
import org.springdoc.core.models.GroupedOpenApi;
6672
import org.springdoc.core.parsers.ReturnTypeParser;
6773
import org.springdoc.core.properties.SpringDocConfigProperties;
@@ -580,4 +586,29 @@ public ResponseEntity<ErrorMessage> handleNoHandlerFound(OpenApiResourceNotFound
580586
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorMessage(e.getMessage()));
581587
}
582588
}
589+
590+
/**
591+
* Spring doc customizers spring doc customizers.
592+
*
593+
* @param openApiCustomizers the open api customizers
594+
* @param operationCustomizers the operation customizers
595+
* @param routerOperationCustomizers the router operation customizers
596+
* @param dataRestRouterOperationCustomizers the data rest router operation customizers
597+
* @param methodFilters the method filters
598+
* @return the spring doc customizers
599+
*/
600+
@Bean
601+
@ConditionalOnMissingBean
602+
@Lazy(false)
603+
public SpringDocCustomizers springDocCustomizers(Optional<List<OpenApiCustomizer>> openApiCustomizers,
604+
Optional<List<OperationCustomizer>> operationCustomizers,
605+
Optional<List<RouterOperationCustomizer>> routerOperationCustomizers,
606+
Optional<List<DataRestRouterOperationCustomizer>> dataRestRouterOperationCustomizers,
607+
Optional<List<OpenApiMethodFilter>> methodFilters){
608+
return new SpringDocCustomizers(openApiCustomizers,
609+
operationCustomizers,
610+
routerOperationCustomizers,
611+
dataRestRouterOperationCustomizers,
612+
methodFilters);
613+
}
583614
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.springdoc.core.customizers;
2+
3+
import org.springdoc.core.fn.RouterOperation;
4+
5+
/**
6+
* The interface Data rest router operation customizer.
7+
*
8+
* @author bnasslahsen
9+
*/
10+
@FunctionalInterface
11+
public interface DataRestRouterOperationCustomizer {
12+
13+
/**
14+
* Customize router operation.
15+
*
16+
* @param routerOperation input operation
17+
* @return customized router operation
18+
*/
19+
RouterOperation customize(RouterOperation routerOperation);
20+
21+
}

0 commit comments

Comments
 (0)