Skip to content

Commit 428702b

Browse files
committedOct 8, 2024·
Swagger doesn't work after custom annotation replacing request parameters. Fixes #2752
1 parent a6c23fb commit 428702b

File tree

5 files changed

+268
-4
lines changed

5 files changed

+268
-4
lines changed
 

Diff for: ‎springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/AbstractRequestService.java

+37-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
* * * *
2222
* * *
2323
* *
24-
*
24+
*
2525
*/
2626

2727
package org.springdoc.core.service;
@@ -63,7 +63,9 @@
6363
import jakarta.validation.constraints.Min;
6464
import jakarta.validation.constraints.Pattern;
6565
import jakarta.validation.constraints.Size;
66+
import org.apache.commons.lang3.ArrayUtils;
6667
import org.apache.commons.lang3.StringUtils;
68+
import org.jetbrains.annotations.NotNull;
6769
import org.springdoc.core.customizers.ParameterCustomizer;
6870
import org.springdoc.core.discoverer.SpringDocParameterNameDiscoverer;
6971
import org.springdoc.core.extractor.DelegatingMethodParameter;
@@ -188,7 +190,7 @@ public abstract class AbstractRequestService {
188190
* @param localSpringDocParameterNameDiscoverer the local spring doc parameter name discoverer
189191
*/
190192
protected AbstractRequestService(GenericParameterService parameterBuilder, RequestBodyService requestBodyService,
191-
Optional<List<ParameterCustomizer>> parameterCustomizers,
193+
Optional<List<ParameterCustomizer>> parameterCustomizers,
192194
SpringDocParameterNameDiscoverer localSpringDocParameterNameDiscoverer) {
193195
super();
194196
this.parameterBuilder = parameterBuilder;
@@ -272,7 +274,7 @@ public static Collection<Parameter> getHeaders(MethodAttributes methodAttributes
272274
public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
273275
Operation operation, MethodAttributes methodAttributes, OpenAPI openAPI) {
274276
// Documentation
275-
String operationId = operation.getOperationId()!=null ? operation.getOperationId() : handlerMethod.getMethod().getName();
277+
String operationId = operation.getOperationId() != null ? operation.getOperationId() : handlerMethod.getMethod().getName();
276278
operation.setOperationId(operationId);
277279
// requests
278280
String[] pNames = this.localSpringDocParameterNameDiscoverer.getParameterNames(handlerMethod.getMethod());
@@ -322,7 +324,9 @@ public Operation build(HandlerMethod handlerMethod, RequestMethod requestMethod,
322324
parameter = buildParams(parameterInfo, components, requestMethod, methodAttributes, openAPI.getOpenapi());
323325
// Merge with the operation parameters
324326
parameter = GenericParameterService.mergeParameter(operationParameters, parameter);
325-
List<Annotation> parameterAnnotations = Arrays.asList(methodParameter.getParameterAnnotations());
327+
328+
List<Annotation> parameterAnnotations = getParameterAnnotations(methodParameter);
329+
326330
if (isValidParameter(parameter)) {
327331
// Add param javadoc
328332
if (StringUtils.isBlank(parameter.getDescription()) && javadocProvider != null) {
@@ -371,6 +375,35 @@ else if (!RequestMethod.GET.equals(requestMethod) || OpenApiVersion.OPENAPI_3_1.
371375
return operation;
372376
}
373377

378+
/**
379+
* Gets parameter annotations.
380+
*
381+
* @param methodParameter the method parameter
382+
* @return the parameter annotations
383+
*/
384+
@NotNull
385+
private static List<Annotation> getParameterAnnotations(MethodParameter methodParameter) {
386+
// Initialize the list for parameter annotations
387+
List<Annotation> parameterAnnotations = new ArrayList<>();
388+
// Add the parameter annotations (direct annotations)
389+
if (ArrayUtils.isNotEmpty(methodParameter.getParameterAnnotations())) {
390+
parameterAnnotations.addAll(Arrays.asList(methodParameter.getParameterAnnotations()));
391+
}
392+
// Separate list to store meta-annotations
393+
List<Annotation> metaAnnotationsList = new ArrayList<>();
394+
// Iterate over the direct annotations and collect meta-annotations
395+
for (Annotation parameterAnnotation : parameterAnnotations) {
396+
Annotation[] metaAnnotations = parameterAnnotation.annotationType().getAnnotations();
397+
398+
if (ArrayUtils.isNotEmpty(metaAnnotations)) {
399+
metaAnnotationsList.addAll(Arrays.asList(metaAnnotations));
400+
}
401+
}
402+
// Add all the collected meta-annotations to the main list
403+
parameterAnnotations.addAll(metaAnnotationsList);
404+
return parameterAnnotations;
405+
}
406+
374407
/**
375408
* Gets parameter linked hash map.
376409
*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * *
6+
* * * * *
7+
* * * * * * Copyright 2019-2024 the original author or authors.
8+
* * * * * *
9+
* * * * * * Licensed under the Apache License, Version 2.0 (the "License");
10+
* * * * * * you may not use this file except in compliance with the License.
11+
* * * * * * You may obtain a copy of the License at
12+
* * * * * *
13+
* * * * * * https://www.apache.org/licenses/LICENSE-2.0
14+
* * * * * *
15+
* * * * * * Unless required by applicable law or agreed to in writing, software
16+
* * * * * * distributed under the License is distributed on an "AS IS" BASIS,
17+
* * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* * * * * * See the License for the specific language governing permissions and
19+
* * * * * * limitations under the License.
20+
* * * * *
21+
* * * *
22+
* * *
23+
* *
24+
*
25+
*/
26+
27+
package test.org.springdoc.api.v30.app229;
28+
29+
import java.lang.annotation.Retention;
30+
import java.lang.annotation.RetentionPolicy;
31+
import java.lang.annotation.Target;
32+
33+
import io.swagger.v3.oas.annotations.Parameter;
34+
import io.swagger.v3.oas.annotations.media.ExampleObject;
35+
import jakarta.validation.Valid;
36+
import jakarta.validation.constraints.Pattern;
37+
import jakarta.validation.constraints.Size;
38+
39+
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
40+
import static java.lang.annotation.ElementType.FIELD;
41+
import static java.lang.annotation.ElementType.METHOD;
42+
import static java.lang.annotation.ElementType.PARAMETER;
43+
44+
/**
45+
* @author bnasslahsen
46+
*/
47+
@Target({PARAMETER, METHOD, FIELD, ANNOTATION_TYPE})
48+
@Retention(RetentionPolicy.RUNTIME)
49+
@Parameter(
50+
examples = {
51+
@ExampleObject(name = "ar-ae"),
52+
@ExampleObject(name = "bg-bg"),
53+
@ExampleObject(name = "cs-cz"),
54+
@ExampleObject(name = "de-de"),
55+
@ExampleObject(name = "el-gr"),
56+
@ExampleObject(name = "en-us.src"),
57+
@ExampleObject(name = "hu-hu"),
58+
@ExampleObject(name = "pl-pl"),
59+
@ExampleObject(name = "ro-ro"),
60+
@ExampleObject(name = "sk-sk")
61+
}
62+
)
63+
@Size(min = 2, max = 16)
64+
@Pattern(regexp = "\\w+([-.]?\\w+)*")
65+
@Valid
66+
@interface LocaleParam {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * *
6+
* * * * *
7+
* * * * * * Copyright 2019-2024 the original author or authors.
8+
* * * * * *
9+
* * * * * * Licensed under the Apache License, Version 2.0 (the "License");
10+
* * * * * * you may not use this file except in compliance with the License.
11+
* * * * * * You may obtain a copy of the License at
12+
* * * * * *
13+
* * * * * * https://www.apache.org/licenses/LICENSE-2.0
14+
* * * * * *
15+
* * * * * * Unless required by applicable law or agreed to in writing, software
16+
* * * * * * distributed under the License is distributed on an "AS IS" BASIS,
17+
* * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* * * * * * See the License for the specific language governing permissions and
19+
* * * * * * limitations under the License.
20+
* * * * *
21+
* * * *
22+
* * *
23+
* *
24+
*
25+
*/
26+
27+
package test.org.springdoc.api.v30.app229;
28+
29+
import test.org.springdoc.api.v30.AbstractSpringDocV30Test;
30+
31+
import org.springframework.boot.autoconfigure.SpringBootApplication;
32+
33+
public class SpringDocApp229Test extends AbstractSpringDocV30Test {
34+
35+
@SpringBootApplication
36+
static class SpringDocTestApp {}
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
*
3+
* *
4+
* * *
5+
* * * *
6+
* * * * *
7+
* * * * * * Copyright 2019-2024 the original author or authors.
8+
* * * * * *
9+
* * * * * * Licensed under the Apache License, Version 2.0 (the "License");
10+
* * * * * * you may not use this file except in compliance with the License.
11+
* * * * * * You may obtain a copy of the License at
12+
* * * * * *
13+
* * * * * * https://www.apache.org/licenses/LICENSE-2.0
14+
* * * * * *
15+
* * * * * * Unless required by applicable law or agreed to in writing, software
16+
* * * * * * distributed under the License is distributed on an "AS IS" BASIS,
17+
* * * * * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
* * * * * * See the License for the specific language governing permissions and
19+
* * * * * * limitations under the License.
20+
* * * * *
21+
* * * *
22+
* * *
23+
* *
24+
*
25+
*/
26+
27+
package test.org.springdoc.api.v30.app229;
28+
29+
30+
import org.springframework.http.ResponseEntity;
31+
import org.springframework.web.bind.annotation.GetMapping;
32+
import org.springframework.web.bind.annotation.RestController;
33+
34+
/**
35+
* @author bnasslahsen
36+
*/
37+
@RestController
38+
public class XController {
39+
40+
41+
@GetMapping("/")
42+
public ResponseEntity<?> manualTranslationUpdateRun(
43+
@LocaleParam String locale) {
44+
//.....
45+
return ResponseEntity.accepted().build();
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
{
2+
"openapi": "3.0.1",
3+
"info": {
4+
"title": "OpenAPI definition",
5+
"version": "v0"
6+
},
7+
"servers": [
8+
{
9+
"url": "http://localhost",
10+
"description": "Generated server url"
11+
}
12+
],
13+
"paths": {
14+
"/": {
15+
"get": {
16+
"tags": [
17+
"x-controller"
18+
],
19+
"operationId": "manualTranslationUpdateRun",
20+
"parameters": [
21+
{
22+
"name": "locale",
23+
"in": "query",
24+
"required": true,
25+
"schema": {
26+
"maxLength": 16,
27+
"minLength": 2,
28+
"pattern": "\\w+([-.]?\\w+)*",
29+
"type": "string"
30+
},
31+
"examples": {
32+
"el-gr": {
33+
"description": "el-gr"
34+
},
35+
"pl-pl": {
36+
"description": "pl-pl"
37+
},
38+
"de-de": {
39+
"description": "de-de"
40+
},
41+
"hu-hu": {
42+
"description": "hu-hu"
43+
},
44+
"en-us.src": {
45+
"description": "en-us.src"
46+
},
47+
"ro-ro": {
48+
"description": "ro-ro"
49+
},
50+
"sk-sk": {
51+
"description": "sk-sk"
52+
},
53+
"bg-bg": {
54+
"description": "bg-bg"
55+
},
56+
"ar-ae": {
57+
"description": "ar-ae"
58+
},
59+
"cs-cz": {
60+
"description": "cs-cz"
61+
}
62+
}
63+
}
64+
],
65+
"responses": {
66+
"200": {
67+
"description": "OK",
68+
"content": {
69+
"*/*": {
70+
"schema": {
71+
"type": "object"
72+
}
73+
}
74+
}
75+
}
76+
}
77+
}
78+
}
79+
},
80+
"components": {}
81+
}

0 commit comments

Comments
 (0)
Please sign in to comment.