Skip to content

Commit 495e88f

Browse files
committed
Changes report: Missing Request Body for Write Operation Actuator Endpoints. Fixes #1565.
1 parent 62e916c commit 495e88f

File tree

8 files changed

+155
-1
lines changed

8 files changed

+155
-1
lines changed

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

+46-1
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,27 @@
2222

2323
package org.springdoc.core.customizers;
2424

25+
import java.lang.reflect.Field;
26+
import java.lang.reflect.Parameter;
2527
import java.util.HashMap;
2628
import java.util.regex.Matcher;
2729
import java.util.regex.Pattern;
2830

31+
import io.swagger.v3.core.util.AnnotationsUtils;
2932
import io.swagger.v3.oas.models.Operation;
33+
import io.swagger.v3.oas.models.media.Content;
34+
import io.swagger.v3.oas.models.media.MediaType;
35+
import io.swagger.v3.oas.models.media.Schema;
36+
import io.swagger.v3.oas.models.parameters.RequestBody;
37+
import org.apache.commons.lang3.reflect.FieldUtils;
38+
import org.slf4j.Logger;
39+
import org.slf4j.LoggerFactory;
3040

41+
import org.springframework.boot.actuate.endpoint.OperationType;
42+
import org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation;
43+
import org.springframework.boot.actuate.endpoint.annotation.Selector;
44+
import org.springframework.boot.actuate.endpoint.invoke.OperationParameter;
45+
import org.springframework.boot.actuate.endpoint.invoke.reflect.OperationMethod;
3146
import org.springframework.web.method.HandlerMethod;
3247

3348
import static org.apache.commons.lang3.math.NumberUtils.INTEGER_ONE;
@@ -44,6 +59,11 @@ public class ActuatorOperationCustomizer implements OperationCustomizer {
4459
*/
4560
private HashMap<String, Integer> methodCountMap = new HashMap<>();
4661

62+
private static final String OPERATION = "operation";
63+
64+
private static final String PARAMETER = "parameter";
65+
66+
private static final Logger LOGGER = LoggerFactory.getLogger(ActuatorOperationCustomizer.class);
4767

4868
/**
4969
* The regex pattern for operationId lookup.
@@ -53,14 +73,39 @@ public class ActuatorOperationCustomizer implements OperationCustomizer {
5373
@Override
5474
public Operation customize(Operation operation, HandlerMethod handlerMethod) {
5575
if (operation.getTags() != null && operation.getTags().contains(getTag().getName())) {
76+
Field operationFiled = FieldUtils.getDeclaredField(handlerMethod.getBean().getClass(), OPERATION, true);
77+
Object actuatorOperation;
78+
if (operationFiled != null) {
79+
try {
80+
actuatorOperation = operationFiled.get(handlerMethod.getBean());
81+
operationFiled = FieldUtils.getDeclaredField(actuatorOperation.getClass(), OPERATION, true);
82+
AbstractDiscoveredOperation discoveredOperation = (AbstractDiscoveredOperation) operationFiled.get(actuatorOperation);
83+
OperationMethod operationMethod = discoveredOperation.getOperationMethod();
84+
if (OperationType.WRITE.equals(operationMethod.getOperationType())) {
85+
for (OperationParameter operationParameter : operationMethod.getParameters()) {
86+
Field parameterField = FieldUtils.getDeclaredField(operationParameter.getClass(), PARAMETER, true);
87+
Parameter parameter = (Parameter) parameterField.get(operationParameter);
88+
Schema<?> schema = AnnotationsUtils.resolveSchemaFromType(parameter.getType(), null, null);
89+
if (parameter.getAnnotation(Selector.class) == null) {
90+
operation.setRequestBody(new RequestBody()
91+
.content(new Content().addMediaType(org.springframework.http.MediaType.APPLICATION_JSON_VALUE, new MediaType().schema(schema))));
92+
}
93+
}
94+
}
95+
}
96+
catch (IllegalAccessException e) {
97+
LOGGER.warn(e.getMessage());
98+
}
99+
}
100+
56101
String summary = handlerMethod.toString();
57102
Matcher matcher = pattern.matcher(summary);
58103
String operationId = operation.getOperationId();
59104
while (matcher.find()) {
60105
operationId = matcher.group(1);
61106
}
62107
if (methodCountMap.containsKey(operationId)) {
63-
Integer methodCount = methodCountMap.get(operationId)+1;
108+
Integer methodCount = methodCountMap.get(operationId) + 1;
64109
methodCountMap.put(operationId, methodCount);
65110
operationId = operationId + "_" + methodCount;
66111
}

springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app146-1.json

+18
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@
7575
}
7676
}
7777
],
78+
"requestBody": {
79+
"content": {
80+
"application/json": {
81+
"schema": {
82+
"type": "string",
83+
"enum": [
84+
"TRACE",
85+
"DEBUG",
86+
"INFO",
87+
"WARN",
88+
"ERROR",
89+
"FATAL",
90+
"OFF"
91+
]
92+
}
93+
}
94+
}
95+
},
7896
"responses": {
7997
"200": {
8098
"description": "OK",

springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app147-1.json

+18
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@
7575
}
7676
}
7777
],
78+
"requestBody": {
79+
"content": {
80+
"application/json": {
81+
"schema": {
82+
"type": "string",
83+
"enum": [
84+
"TRACE",
85+
"DEBUG",
86+
"INFO",
87+
"WARN",
88+
"ERROR",
89+
"FATAL",
90+
"OFF"
91+
]
92+
}
93+
}
94+
}
95+
},
7896
"responses": {
7997
"200": {
8098
"description": "OK",

springdoc-openapi-tests/springdoc-openapi-actuator-webflux-tests/src/test/resources/results/app148-2.json

+18
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@
7575
}
7676
}
7777
],
78+
"requestBody": {
79+
"content": {
80+
"application/json": {
81+
"schema": {
82+
"type": "string",
83+
"enum": [
84+
"TRACE",
85+
"DEBUG",
86+
"INFO",
87+
"WARN",
88+
"ERROR",
89+
"FATAL",
90+
"OFF"
91+
]
92+
}
93+
}
94+
}
95+
},
7896
"responses": {
7997
"200": {
8098
"description": "OK",

springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/java/test/org/springdoc/api/app148/SpringDocApp148Test.java

+1
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public void testApp() throws Exception {
5555
@Test
5656
public void testApp2() throws Exception {
5757
String result = actuatorRestTemplate.getForObject("/test/application/openapi/x-actuator", String.class);
58+
System.out.println(result);
5859
String expected = getContent("results/app148-2.json");
5960
assertEquals(expected, result, true);
6061
}

springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app146-1.json

+18
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,24 @@
7777
}
7878
}
7979
],
80+
"requestBody": {
81+
"content": {
82+
"application/json": {
83+
"schema": {
84+
"type": "string",
85+
"enum": [
86+
"TRACE",
87+
"DEBUG",
88+
"INFO",
89+
"WARN",
90+
"ERROR",
91+
"FATAL",
92+
"OFF"
93+
]
94+
}
95+
}
96+
}
97+
},
8098
"responses": {
8199
"200": {
82100
"description": "OK",

springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app147-1.json

+18
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,24 @@
7777
}
7878
}
7979
],
80+
"requestBody": {
81+
"content": {
82+
"application/json": {
83+
"schema": {
84+
"type": "string",
85+
"enum": [
86+
"TRACE",
87+
"DEBUG",
88+
"INFO",
89+
"WARN",
90+
"ERROR",
91+
"FATAL",
92+
"OFF"
93+
]
94+
}
95+
}
96+
}
97+
},
8098
"responses": {
8199
"200": {
82100
"description": "OK",

springdoc-openapi-tests/springdoc-openapi-actuator-webmvc-tests/src/test/resources/results/app148-2.json

+18
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,24 @@
7777
}
7878
}
7979
],
80+
"requestBody": {
81+
"content": {
82+
"application/json": {
83+
"schema": {
84+
"type": "string",
85+
"enum": [
86+
"TRACE",
87+
"DEBUG",
88+
"INFO",
89+
"WARN",
90+
"ERROR",
91+
"FATAL",
92+
"OFF"
93+
]
94+
}
95+
}
96+
}
97+
},
8098
"responses": {
8199
"200": {
82100
"description": "OK",

0 commit comments

Comments
 (0)