1818
1919package org .springdoc .webflux .api ;
2020
21+ import java .lang .annotation .Annotation ;
22+ import java .lang .reflect .Method ;
23+ import java .util .ArrayList ;
24+ import java .util .Arrays ;
25+ import java .util .HashSet ;
2126import java .util .LinkedHashMap ;
2227import java .util .List ;
2328import java .util .Map ;
3035import io .swagger .v3 .core .util .Yaml ;
3136import io .swagger .v3 .oas .annotations .Operation ;
3237import io .swagger .v3 .oas .models .OpenAPI ;
38+ import org .apache .commons .lang3 .ArrayUtils ;
39+ import org .apache .commons .lang3 .StringUtils ;
40+ import org .slf4j .Logger ;
41+ import org .slf4j .LoggerFactory ;
3342import org .springdoc .api .AbstractOpenApiResource ;
3443import org .springdoc .core .AbstractRequestBuilder ;
3544import org .springdoc .core .GenericResponseBuilder ;
3847import org .springdoc .core .SpringDocConfigProperties ;
3948import org .springdoc .core .customizers .OpenApiCustomiser ;
4049import org .springdoc .core .customizers .OperationCustomizer ;
50+ import org .springdoc .webflux .annotations .RouterOperation ;
51+ import org .springdoc .webflux .annotations .RouterOperations ;
4152import reactor .core .publisher .Mono ;
4253
4354import org .springframework .beans .factory .annotation .Autowired ;
4455import org .springframework .beans .factory .annotation .Value ;
56+ import org .springframework .beans .factory .config .BeanDefinition ;
57+ import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
58+ import org .springframework .context .ApplicationContext ;
59+ import org .springframework .core .type .StandardMethodMetadata ;
4560import org .springframework .http .MediaType ;
4661import org .springframework .http .server .reactive .ServerHttpRequest ;
62+ import org .springframework .util .CollectionUtils ;
4763import org .springframework .web .bind .annotation .GetMapping ;
4864import org .springframework .web .bind .annotation .RequestMethod ;
4965import org .springframework .web .bind .annotation .RestController ;
5066import org .springframework .web .method .HandlerMethod ;
67+ import org .springframework .web .reactive .HandlerMapping ;
68+ import org .springframework .web .reactive .function .server .RouterFunction ;
5169import org .springframework .web .reactive .result .condition .PatternsRequestCondition ;
5270import org .springframework .web .reactive .result .method .RequestMappingInfo ;
5371import org .springframework .web .reactive .result .method .RequestMappingInfoHandlerMapping ;
6280@ RestController
6381public class OpenApiResource extends AbstractOpenApiResource {
6482
83+ private static final Logger LOGGER = LoggerFactory .getLogger (OpenApiResource .class );
84+
6585 private final RequestMappingInfoHandlerMapping requestMappingHandlerMapping ;
6686
87+ @ Autowired
88+ private List <HandlerMapping > handlerMappings ;
89+
6790 public OpenApiResource (String groupName , OpenAPIBuilder openAPIBuilder , AbstractRequestBuilder requestBuilder ,
6891 GenericResponseBuilder responseBuilder , OperationBuilder operationParser ,
6992 RequestMappingInfoHandlerMapping requestMappingHandlerMapping ,
@@ -79,7 +102,7 @@ public OpenApiResource(OpenAPIBuilder openAPIBuilder, AbstractRequestBuilder req
79102 RequestMappingInfoHandlerMapping requestMappingHandlerMapping ,
80103 Optional <List <OperationCustomizer >> operationCustomizers ,
81104 Optional <List <OpenApiCustomiser >> openApiCustomisers , SpringDocConfigProperties springDocConfigProperties ) {
82- super (DEFAULT_GROUP_NAME , openAPIBuilder , requestBuilder , responseBuilder , operationParser ,operationCustomizers , openApiCustomisers , springDocConfigProperties );
105+ super (DEFAULT_GROUP_NAME , openAPIBuilder , requestBuilder , responseBuilder , operationParser , operationCustomizers , openApiCustomisers , springDocConfigProperties );
83106 this .requestMappingHandlerMapping = requestMappingHandlerMapping ;
84107 }
85108
@@ -123,6 +146,51 @@ protected void getPaths(Map<String, Object> restControllers) {
123146 }
124147 }
125148 }
149+
150+ ApplicationContext applicationContext = (ApplicationContext ) requestMappingHandlerMapping .getApplicationContext ();
151+ Map <String , RouterFunction > routerBeans = applicationContext .getBeansOfType (RouterFunction .class );
152+
153+ for (Map .Entry <String , RouterFunction > entry : routerBeans .entrySet ()) {
154+ List <RouterOperation > routerOperationList = new ArrayList <>();
155+ RouterOperations routerOperations = applicationContext .findAnnotationOnBean (entry .getKey (), RouterOperations .class );
156+ if (routerOperations == null ) {
157+ RouterOperation routerOperation = applicationContext .findAnnotationOnBean (entry .getKey (), RouterOperation .class );
158+ routerOperationList .add (routerOperation );
159+ }
160+ else
161+ routerOperationList .addAll (Arrays .asList (routerOperations .value ()));
162+
163+ if (!CollectionUtils .isEmpty (routerOperationList )) {
164+ for (RouterOperation routerOperation : routerOperationList ) {
165+ if (!Void .class .equals (routerOperation .beanClass ())) {
166+ Object handlerBean = applicationContext .getBean (routerOperation .beanClass ());
167+ HandlerMethod handlerMethod = null ;
168+ if (StringUtils .isNotBlank (routerOperation .beanMethod ())) {
169+ try {
170+ if (ArrayUtils .isEmpty (routerOperation .parameterTypes ())) {
171+ Optional <Method > methodOptional = Arrays .stream (handlerBean .getClass ().getDeclaredMethods ())
172+ .filter (method1 -> routerOperation .beanMethod ().equals (method1 .getName ()) && method1 .getParameters ().length == 0 )
173+ .findAny ();
174+ if (!methodOptional .isPresent ())
175+ methodOptional = Arrays .stream (handlerBean .getClass ().getDeclaredMethods ())
176+ .filter (method1 -> routerOperation .beanMethod ().equals (method1 .getName ()))
177+ .findAny ();
178+ if (methodOptional .isPresent ())
179+ handlerMethod = new HandlerMethod (handlerBean , methodOptional .get ());
180+ }
181+ else
182+ handlerMethod = new HandlerMethod (handlerBean , routerOperation .beanMethod (), routerOperation .parameterTypes ());
183+ }
184+ catch (NoSuchMethodException e ) {
185+ LOGGER .error (e .getMessage ());
186+ }
187+ if (handlerMethod != null )
188+ calculatePath (handlerMethod , routerOperation .path (), new HashSet <>(Arrays .asList (routerOperation .method ())));
189+ }
190+ }
191+ }
192+ }
193+ }
126194 }
127195
128196 protected void calculateServerUrl (ServerHttpRequest serverHttpRequest , String apiDocsUrl ) {
@@ -131,4 +199,23 @@ protected void calculateServerUrl(ServerHttpRequest serverHttpRequest, String ap
131199 openAPIBuilder .setServerBaseUrl (serverBaseUrl );
132200 }
133201
202+ public List <String > getBeansWithAnnotation (ConfigurableListableBeanFactory factory , Class <? extends Annotation > type ) {
203+
204+ List <String > result = new ArrayList <>();
205+
206+ for (String name : factory .getBeanDefinitionNames ()) {
207+ BeanDefinition bd = factory .getBeanDefinition (name );
208+
209+ if (bd .getSource () instanceof StandardMethodMetadata ) {
210+ StandardMethodMetadata metadata = (StandardMethodMetadata ) bd .getSource ();
211+
212+ Map <String , Object > attributes = metadata .getAnnotationAttributes (type .getName ());
213+ if (null == attributes ) {
214+ continue ;
215+ }
216+ }
217+ }
218+
219+ return result ;
220+ }
134221}
0 commit comments