Skip to content

Commit 9f6632a

Browse files
author
bnasslahsen
committed
Generate api-docs for Custom Actuator Endpoint. Fixes #786
1 parent 1c569b1 commit 9f6632a

File tree

11 files changed

+293
-54
lines changed

11 files changed

+293
-54
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import io.swagger.v3.oas.models.ExternalDocumentation;
2626
import io.swagger.v3.oas.models.tags.Tag;
27+
import org.springdoc.api.AbstractOpenApiResource;
2728

2829
import org.springframework.util.AntPathMatcher;
2930

@@ -64,8 +65,9 @@ default Tag getTag() {
6465
* @param operationPath the operation path
6566
* @return the boolean
6667
*/
67-
default boolean isRestController(String operationPath) {
68-
return operationPath.startsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR);
68+
default boolean isRestController(String operationPath, Class<?> controllerClass) {
69+
return operationPath.startsWith(AntPathMatcher.DEFAULT_PATH_SEPARATOR)
70+
&& !AbstractOpenApiResource.isHiddenRestControllers(controllerClass);
6971
}
7072

7173
}

springdoc-openapi-common/src/main/java/org/springdoc/core/customizers/ActuatorOpenApiCustomiser.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package org.springdoc.core.customizers;
22

3+
import java.util.List;
4+
import java.util.Optional;
35
import java.util.regex.Matcher;
46
import java.util.regex.Pattern;
57

68
import io.swagger.v3.oas.models.OpenAPI;
79
import io.swagger.v3.oas.models.PathItem;
810
import io.swagger.v3.oas.models.media.StringSchema;
11+
import io.swagger.v3.oas.models.parameters.Parameter;
912
import io.swagger.v3.oas.models.parameters.PathParameter;
1013

14+
import org.springframework.util.CollectionUtils;
15+
1116
/**
1217
* The type Actuator open api customiser.
1318
* @author bnasslahsen
@@ -26,7 +31,14 @@ public void customise(OpenAPI openApi) {
2631
while (matcher.find()) {
2732
String pathParam = matcher.group(1);
2833
PathItem pathItem = stringPathItemEntry.getValue();
29-
pathItem.readOperations().forEach(operation -> operation.addParametersItem(new PathParameter().name(pathParam).schema(new StringSchema())));
34+
pathItem.readOperations().forEach(operation -> {
35+
List<Parameter> existingParameters = operation.getParameters();
36+
Optional<Parameter> existingParam = Optional.empty();
37+
if (!CollectionUtils.isEmpty(existingParameters))
38+
existingParam = existingParameters.stream().filter(p -> pathParam.equals(p.getName())).findAny();
39+
if (!existingParam.isPresent())
40+
operation.addParametersItem(new PathParameter().name(pathParam).schema(new StringSchema()));
41+
});
3042
}
3143
});
3244
}

springdoc-openapi-webflux-core/src/main/java/org/springdoc/webflux/core/SpringDocWebFluxConfiguration.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.beans.factory.ObjectFactory;
4545
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
4646
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
47+
import org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping;
4748
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
4849
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
4950
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -156,13 +157,14 @@ static class SpringDocWebFluxActuatorConfiguration {
156157
/**
157158
* Actuator provider actuator provider.
158159
*
159-
* @param webFluxEndpointHandlerMapping the web flux endpoint handler mapping
160+
* @param webFluxEndpointHandlerMapping the web flux endpoint handler mapping
161+
* @param controllerEndpointHandlerMapping the controller endpoint handler mapping
160162
* @return the actuator provider
161163
*/
162164
@Bean
163165
@ConditionalOnMissingBean
164-
ActuatorProvider actuatorProvider(WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping) {
165-
return new WebFluxActuatorProvider(webFluxEndpointHandlerMapping);
166+
ActuatorProvider actuatorProvider(WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping, ControllerEndpointHandlerMapping controllerEndpointHandlerMapping) {
167+
return new WebFluxActuatorProvider(webFluxEndpointHandlerMapping, controllerEndpointHandlerMapping);
166168
}
167169

168170
/**

springdoc-openapi-webflux-core/src/main/java/org/springdoc/webflux/core/WebFluxActuatorProvider.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020

2121
package org.springdoc.webflux.core;
2222

23+
import java.util.HashMap;
2324
import java.util.Map;
2425

2526
import org.springdoc.core.ActuatorProvider;
2627

28+
import org.springframework.boot.actuate.endpoint.web.reactive.ControllerEndpointHandlerMapping;
2729
import org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping;
2830
import org.springframework.web.method.HandlerMethod;
2931
import org.springframework.web.reactive.result.method.RequestMappingInfo;
@@ -40,16 +42,26 @@ public class WebFluxActuatorProvider implements ActuatorProvider {
4042
*/
4143
private final WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping;
4244

45+
/**
46+
* The Controller endpoint handler mapping.
47+
*/
48+
private final ControllerEndpointHandlerMapping controllerEndpointHandlerMapping;
49+
4350
/**
4451
* Instantiates a new Web flux actuator provider.
4552
*
4653
* @param webFluxEndpointHandlerMapping the web flux endpoint handler mapping
54+
* @param controllerEndpointHandlerMapping the controller endpoint handler mapping
4755
*/
48-
public WebFluxActuatorProvider(WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping) {
56+
public WebFluxActuatorProvider(WebFluxEndpointHandlerMapping webFluxEndpointHandlerMapping, ControllerEndpointHandlerMapping controllerEndpointHandlerMapping) {
4957
this.webFluxEndpointHandlerMapping = webFluxEndpointHandlerMapping;
58+
this.controllerEndpointHandlerMapping = controllerEndpointHandlerMapping;
5059
}
5160

5261
public Map<RequestMappingInfo, HandlerMethod> getMethods() {
53-
return webFluxEndpointHandlerMapping.getHandlerMethods();
62+
Map<RequestMappingInfo, HandlerMethod> mappingInfoHandlerMethodMap = new HashMap<>();
63+
mappingInfoHandlerMethodMap.putAll(webFluxEndpointHandlerMapping.getHandlerMethods());
64+
mappingInfoHandlerMethodMap.putAll(controllerEndpointHandlerMapping.getHandlerMethods());
65+
return mappingInfoHandlerMethodMap;
5466
}
5567
}

springdoc-openapi-webflux-core/src/test/resources/results/app76.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,38 @@
2525
}
2626
],
2727
"paths": {
28-
"/actuator/info": {
28+
"/actuator": {
2929
"get": {
3030
"tags": [
3131
"Actuator"
3232
],
33-
"operationId": "handle",
33+
"operationId": "links",
3434
"responses": {
3535
"200": {
3636
"description": "OK",
3737
"content": {
3838
"*/*": {
3939
"schema": {
40-
"$ref": "#/components/schemas/PublisherResponseEntityObject"
40+
"type": "object",
41+
"additionalProperties": {
42+
"type": "object",
43+
"additionalProperties": {
44+
"$ref": "#/components/schemas/Link"
45+
}
46+
}
4147
}
4248
}
4349
}
4450
}
4551
}
4652
}
4753
},
48-
"/actuator/health": {
54+
"/actuator/info": {
4955
"get": {
5056
"tags": [
5157
"Actuator"
5258
],
53-
"operationId": "handle_1",
59+
"operationId": "handle",
5460
"responses": {
5561
"200": {
5662
"description": "OK",
@@ -65,25 +71,19 @@
6571
}
6672
}
6773
},
68-
"/actuator": {
74+
"/actuator/health": {
6975
"get": {
7076
"tags": [
7177
"Actuator"
7278
],
73-
"operationId": "links",
79+
"operationId": "handle_1",
7480
"responses": {
7581
"200": {
7682
"description": "OK",
7783
"content": {
7884
"*/*": {
7985
"schema": {
80-
"type": "object",
81-
"additionalProperties": {
82-
"type": "object",
83-
"additionalProperties": {
84-
"$ref": "#/components/schemas/Link"
85-
}
86-
}
86+
"$ref": "#/components/schemas/PublisherResponseEntityObject"
8787
}
8888
}
8989
}
@@ -94,9 +94,6 @@
9494
},
9595
"components": {
9696
"schemas": {
97-
"PublisherResponseEntityObject": {
98-
"type": "object"
99-
},
10097
"Link": {
10198
"type": "object",
10299
"properties": {
@@ -107,6 +104,9 @@
107104
"type": "boolean"
108105
}
109106
}
107+
},
108+
"PublisherResponseEntityObject": {
109+
"type": "object"
110110
}
111111
},
112112
"securitySchemes": {

springdoc-openapi-webmvc-core/src/main/java/org/springdoc/webmvc/api/OpenApiResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ protected void calculatePath(Map<String, Object> restControllers, Map<RequestMap
248248
Map<String, String> regexMap = new LinkedHashMap<>();
249249
for (String pattern : patterns) {
250250
String operationPath = PathUtils.parsePath(pattern, regexMap);
251-
if (((actuatorProvider.isPresent() && actuatorProvider.get().isRestController(operationPath))
251+
if (((actuatorProvider.isPresent() && actuatorProvider.get().isRestController(operationPath, handlerMethod.getBeanType()))
252252
|| isRestController(restControllers, handlerMethod, operationPath))
253253
&& isPackageToScan(handlerMethod.getBeanType().getPackage())
254254
&& isPathToMatch(operationPath)) {

springdoc-openapi-webmvc-core/src/main/java/org/springdoc/webmvc/api/WebMvcActuatorProvider.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020

2121
package org.springdoc.webmvc.api;
2222

23+
import java.util.HashMap;
2324
import java.util.Map;
2425

2526
import org.springdoc.core.ActuatorProvider;
2627

28+
import org.springframework.boot.actuate.endpoint.web.servlet.ControllerEndpointHandlerMapping;
2729
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
2830
import org.springframework.web.method.HandlerMethod;
2931
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
@@ -40,18 +42,28 @@ public class WebMvcActuatorProvider implements ActuatorProvider {
4042
*/
4143
private final WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping;
4244

45+
/**
46+
* The Controller endpoint handler mapping.
47+
*/
48+
private final ControllerEndpointHandlerMapping controllerEndpointHandlerMapping;
49+
4350
/**
4451
* Instantiates a new Web mvc actuator provider.
4552
*
4653
* @param webMvcEndpointHandlerMapping the web mvc endpoint handler mapping
54+
* @param controllerEndpointHandlerMapping the controller endpoint handler mapping
4755
*/
48-
public WebMvcActuatorProvider(WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping) {
56+
public WebMvcActuatorProvider(WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping, ControllerEndpointHandlerMapping controllerEndpointHandlerMapping) {
4957
this.webMvcEndpointHandlerMapping = webMvcEndpointHandlerMapping;
58+
this.controllerEndpointHandlerMapping = controllerEndpointHandlerMapping;
5059
}
5160

5261
@Override
5362
public Map<RequestMappingInfo, HandlerMethod> getMethods() {
54-
return webMvcEndpointHandlerMapping.getHandlerMethods();
63+
Map<RequestMappingInfo, HandlerMethod> mappingInfoHandlerMethodMap = new HashMap<>();
64+
mappingInfoHandlerMethodMap.putAll(webMvcEndpointHandlerMapping.getHandlerMethods());
65+
mappingInfoHandlerMethodMap.putAll(controllerEndpointHandlerMapping.getHandlerMethods());
66+
return mappingInfoHandlerMethodMap;
5567
}
5668

5769
}

springdoc-openapi-webmvc-core/src/main/java/org/springdoc/webmvc/core/SpringDocWebMvcConfiguration.java

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
import org.springframework.beans.factory.ObjectFactory;
4848
import org.springframework.boot.actuate.autoconfigure.web.server.ConditionalOnManagementPort;
4949
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
50+
import org.springframework.boot.actuate.endpoint.web.servlet.ControllerEndpointHandlerMapping;
5051
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
5152
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
5253
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -75,18 +76,18 @@ public class SpringDocWebMvcConfiguration {
7576
/**
7677
* Open api resource open api resource.
7778
*
78-
* @param openAPIBuilderObjectFactory the open api builder object factory
79-
* @param requestBuilder the request builder
80-
* @param responseBuilder the response builder
81-
* @param operationParser the operation parser
82-
* @param requestMappingHandlerMapping the request mapping handler mapping
83-
* @param actuatorProvider the actuator provider
84-
* @param springDocConfigProperties the spring doc config properties
85-
* @param operationCustomizers the operation customizers
86-
* @param openApiCustomisers the open api customisers
87-
* @param springSecurityOAuth2Provider the spring security o auth 2 provider
88-
* @param routerFunctionProvider the router function provider
89-
* @param repositoryRestResourceProvider the repository rest resource provider
79+
* @param openAPIBuilderObjectFactory the open api builder object factory
80+
* @param requestBuilder the request builder
81+
* @param responseBuilder the response builder
82+
* @param operationParser the operation parser
83+
* @param requestMappingHandlerMapping the request mapping handler mapping
84+
* @param actuatorProvider the actuator provider
85+
* @param springDocConfigProperties the spring doc config properties
86+
* @param operationCustomizers the operation customizers
87+
* @param openApiCustomisers the open api customisers
88+
* @param springSecurityOAuth2Provider the spring security o auth 2 provider
89+
* @param routerFunctionProvider the router function provider
90+
* @param repositoryRestResourceProvider the repository rest resource provider
9091
* @return the open api resource
9192
*/
9293
@Bean
@@ -112,11 +113,11 @@ OpenApiResource openApiResource(ObjectFactory<OpenAPIBuilder> openAPIBuilderObje
112113
/**
113114
* Request builder request builder.
114115
*
115-
* @param parameterBuilder the parameter builder
116-
* @param requestBodyBuilder the request body builder
117-
* @param operationBuilder the operation builder
118-
* @param parameterCustomizers the parameter customizers
119-
* @param localSpringDocParameterNameDiscoverer the local spring doc parameter name discoverer
116+
* @param parameterBuilder the parameter builder
117+
* @param requestBodyBuilder the request body builder
118+
* @param operationBuilder the operation builder
119+
* @param parameterCustomizers the parameter customizers
120+
* @param localSpringDocParameterNameDiscoverer the local spring doc parameter name discoverer
120121
* @return the request builder
121122
*/
122123
@Bean
@@ -131,10 +132,10 @@ RequestBuilder requestBuilder(GenericParameterBuilder parameterBuilder, RequestB
131132
/**
132133
* Response builder generic response builder.
133134
*
134-
* @param operationBuilder the operation builder
135-
* @param returnTypeParsers the return type parsers
136-
* @param springDocConfigProperties the spring doc config properties
137-
* @param propertyResolverUtils the property resolver utils
135+
* @param operationBuilder the operation builder
136+
* @param returnTypeParsers the return type parsers
137+
* @param springDocConfigProperties the spring doc config properties
138+
* @param propertyResolverUtils the property resolver utils
138139
* @return the generic response builder
139140
*/
140141
@Bean
@@ -153,7 +154,7 @@ class SpringDocWebMvcRouterConfiguration {
153154
/**
154155
* Router function provider router function provider.
155156
*
156-
* @param applicationContext the application context
157+
* @param applicationContext the application context
157158
* @return the router function provider
158159
*/
159160
@Bean
@@ -175,19 +176,20 @@ static class SpringDocWebMvcActuatorConfiguration {
175176
/**
176177
* Actuator provider actuator provider.
177178
*
178-
* @param webMvcEndpointHandlerMapping the web mvc endpoint handler mapping
179+
* @param webMvcEndpointHandlerMapping the web mvc endpoint handler mapping
180+
* @param controllerEndpointHandlerMapping the controller endpoint handler mapping
179181
* @return the actuator provider
180182
*/
181183
@Bean
182184
@ConditionalOnMissingBean
183-
ActuatorProvider actuatorProvider(WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping) {
184-
return new WebMvcActuatorProvider(webMvcEndpointHandlerMapping);
185+
ActuatorProvider actuatorProvider(WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping, ControllerEndpointHandlerMapping controllerEndpointHandlerMapping) {
186+
return new WebMvcActuatorProvider(webMvcEndpointHandlerMapping, controllerEndpointHandlerMapping);
185187
}
186188

187189
/**
188190
* Actuator customizer operation customizer.
189191
*
190-
* @param actuatorProvider the actuator provider
192+
* @param actuatorProvider the actuator provider
191193
* @return the operation customizer
192194
*/
193195
@Bean

0 commit comments

Comments
 (0)