51
51
import org .springframework .web .bind .annotation .ExceptionHandler ;
52
52
import org .springframework .web .bind .annotation .RequestMapping ;
53
53
import org .springframework .web .bind .annotation .ResponseStatus ;
54
+ import org .springframework .web .method .ControllerAdviceBean ;
54
55
import org .springframework .web .method .HandlerMethod ;
55
56
56
57
import static org .springdoc .core .Constants .DEFAULT_DESCRIPTION ;
59
60
@ SuppressWarnings ("rawtypes" )
60
61
public class GenericResponseBuilder {
61
62
62
- private final Map < String , ApiResponse > genericMapResponse = new LinkedHashMap <>();
63
+ private List < ControllerAdviceInfo > controllerAdviceInfos = new ArrayList <>();
63
64
64
65
private final OperationBuilder operationBuilder ;
65
66
@@ -81,8 +82,7 @@ public GenericResponseBuilder(OperationBuilder operationBuilder, List<ReturnType
81
82
82
83
public ApiResponses build (Components components , HandlerMethod handlerMethod , Operation operation ,
83
84
MethodAttributes methodAttributes ) {
84
- ApiResponses apiResponses = new ApiResponses ();
85
- genericMapResponse .forEach (apiResponses ::addApiResponse );
85
+ ApiResponses apiResponses = methodAttributes .calculateGenericMapResponse (getGenericMapResponse (handlerMethod .getBeanType ()));
86
86
//Then use the apiResponses from documentation
87
87
ApiResponses apiResponsesFromDoc = operation .getResponses ();
88
88
if (!CollectionUtils .isEmpty (apiResponsesFromDoc ))
@@ -95,32 +95,31 @@ public ApiResponses build(Components components, HandlerMethod handlerMethod, Op
95
95
96
96
public void buildGenericResponse (Components components , Map <String , Object > findControllerAdvice ) {
97
97
// ControllerAdvice
98
- List <Method > methods = getMethods (findControllerAdvice );
99
- // for each one build ApiResponse and add it to existing responses
100
- for (Method method : methods ) {
101
- if (!operationBuilder .isHidden (method )) {
102
- RequestMapping reqMappringMethod = AnnotatedElementUtils .findMergedAnnotation (method , RequestMapping .class );
103
- String [] methodProduces = { springDocConfigProperties .getDefaultProducesMediaType () };
104
- if (reqMappringMethod != null )
105
- methodProduces = reqMappringMethod .produces ();
106
- Map <String , ApiResponse > apiResponses = computeResponse (components , new MethodParameter (method , -1 ), new ApiResponses (),
107
- new MethodAttributes (methodProduces , springDocConfigProperties .getDefaultConsumesMediaType (), springDocConfigProperties .getDefaultProducesMediaType ()), true );
108
- apiResponses .forEach (genericMapResponse ::put );
109
- }
110
- }
111
- }
112
-
113
- private List <Method > getMethods (Map <String , Object > findControllerAdvice ) {
114
- List <Method > methods = new ArrayList <>();
115
98
for (Map .Entry <String , Object > entry : findControllerAdvice .entrySet ()) {
99
+ List <Method > methods = new ArrayList <>();
116
100
Object controllerAdvice = entry .getValue ();
117
101
// get all methods with annotation @ExceptionHandler
118
102
Class <?> objClz = controllerAdvice .getClass ();
119
103
if (org .springframework .aop .support .AopUtils .isAopProxy (controllerAdvice ))
120
104
objClz = org .springframework .aop .support .AopUtils .getTargetClass (controllerAdvice );
105
+ ControllerAdviceInfo controllerAdviceInfo = new ControllerAdviceInfo (controllerAdvice );
121
106
Arrays .stream (objClz .getDeclaredMethods ()).filter (m -> m .isAnnotationPresent (ExceptionHandler .class )).forEach (methods ::add );
107
+ // for each one build ApiResponse and add it to existing responses
108
+ for (Method method : methods ) {
109
+ if (!operationBuilder .isHidden (method )) {
110
+ RequestMapping reqMappringMethod = AnnotatedElementUtils .findMergedAnnotation (method , RequestMapping .class );
111
+ String [] methodProduces = { springDocConfigProperties .getDefaultProducesMediaType () };
112
+ if (reqMappringMethod != null )
113
+ methodProduces = reqMappringMethod .produces ();
114
+ Map <String , ApiResponse > controllerAdviceInfoApiResponseMap = controllerAdviceInfo .getApiResponseMap ();
115
+ Map <String , ApiResponse > apiResponses = computeResponse (components , new MethodParameter (method , -1 ), new ApiResponses (),
116
+ new MethodAttributes (methodProduces , springDocConfigProperties .getDefaultConsumesMediaType (),
117
+ springDocConfigProperties .getDefaultProducesMediaType (), controllerAdviceInfoApiResponseMap ), true );
118
+ apiResponses .forEach (controllerAdviceInfoApiResponseMap ::put );
119
+ }
120
+ }
121
+ controllerAdviceInfos .add (controllerAdviceInfo );
122
122
}
123
- return methods ;
124
123
}
125
124
126
125
private Map <String , ApiResponse > computeResponse (Components components , MethodParameter methodParameter , ApiResponses apiResponsesOp ,
@@ -130,7 +129,7 @@ private Map<String, ApiResponse> computeResponse(Components components, MethodPa
130
129
if (!responsesArray .isEmpty ()) {
131
130
methodAttributes .setWithApiResponseDoc (true );
132
131
if (!springDocConfigProperties .isOverrideWithGenericResponse ())
133
- for (String key : genericMapResponse .keySet ())
132
+ for (String key : methodAttributes . getGenericMapResponse () .keySet ())
134
133
apiResponsesOp .remove (key );
135
134
for (io .swagger .v3 .oas .annotations .responses .ApiResponse apiResponseAnnotations : responsesArray ) {
136
135
ApiResponse apiResponse = new ApiResponse ();
@@ -181,7 +180,7 @@ private void buildContentFromDoc(Components components, ApiResponses apiResponse
181
180
182
181
private void buildApiResponses (Components components , MethodParameter methodParameter , ApiResponses apiResponsesOp ,
183
182
MethodAttributes methodAttributes , boolean isGeneric ) {
184
- if (!CollectionUtils .isEmpty (apiResponsesOp ) && (apiResponsesOp .size () != genericMapResponse .size () || isGeneric )) {
183
+ if (!CollectionUtils .isEmpty (apiResponsesOp ) && (apiResponsesOp .size () != methodAttributes . getGenericMapResponse () .size () || isGeneric )) {
185
184
// API Responses at operation and @ApiResponse annotation
186
185
for (Map .Entry <String , ApiResponse > entry : apiResponsesOp .entrySet ()) {
187
186
String httpCode = entry .getKey ();
@@ -194,7 +193,7 @@ private void buildApiResponses(Components components, MethodParameter methodPara
194
193
// Use response parameters with no description filled - No documentation
195
194
// available
196
195
String httpCode = evaluateResponseStatus (methodParameter .getMethod (), methodParameter .getMethod ().getClass (), isGeneric );
197
- ApiResponse apiResponse = genericMapResponse . containsKey (httpCode ) ? genericMapResponse .get (httpCode )
196
+ ApiResponse apiResponse = methodAttributes . getGenericMapResponse (). containsKey (httpCode ) ? methodAttributes . getGenericMapResponse () .get (httpCode )
198
197
: new ApiResponse ();
199
198
if (httpCode != null )
200
199
buildApiResponses (components , methodParameter , apiResponsesOp , methodAttributes , httpCode , apiResponse ,
@@ -345,4 +344,11 @@ else if (returnType instanceof ParameterizedType) {
345
344
result = true ;
346
345
return result ;
347
346
}
347
+
348
+ private Map <String , ApiResponse > getGenericMapResponse (Class <?> beanType ) {
349
+ return controllerAdviceInfos .stream ()
350
+ .filter (controllerAdviceInfo -> new ControllerAdviceBean (controllerAdviceInfo .getControllerAdvice ()).isApplicableToBeanType (beanType ))
351
+ .map (ControllerAdviceInfo ::getApiResponseMap )
352
+ .collect (LinkedHashMap ::new , Map ::putAll , Map ::putAll );
353
+ }
348
354
}
0 commit comments