Skip to content

Commit e7652ec

Browse files
committed
Refactor webhook discovery and scanning mechanism
- Introduce `getWebhooksClasses()` method to retrieve webhook-related classes - Modify `getWebhooks()` to accept an array of classes - Improve webhook class discovery process - Add package filtering in `calculateWebhooks()` Fixes #3056
1 parent a297959 commit e7652ec

File tree

3 files changed

+76
-60
lines changed

3 files changed

+76
-60
lines changed

springdoc-openapi-starter-common/src/main/java/org/springdoc/api/AbstractOpenApiResource.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@
140140
* @author kevinraddatz
141141
* @author hyeonisism
142142
* @author doljae
143+
* @author zdary
143144
*/
144145
public abstract class AbstractOpenApiResource extends SpecFilter {
145146

@@ -523,8 +524,12 @@ private void trimIndentOperation(Operation operation) {
523524
* @param locale the locale
524525
*/
525526
protected void calculateWebhooks(OpenAPI calculatedOpenAPI, Locale locale) {
526-
Webhooks[] webhooksAttr = openAPIService.getWebhooks();
527-
if (ArrayUtils.isEmpty(webhooksAttr))
527+
Class<?>[] classes = openAPIService.getWebhooksClasses();
528+
Class<?>[] refinedClasses = Arrays.stream(classes)
529+
.filter(clazz -> isPackageToScan(clazz.getPackage()))
530+
.toArray(Class<?>[]::new);
531+
Webhooks[] webhooksAttr = openAPIService.getWebhooks(refinedClasses);
532+
if (ArrayUtils.isEmpty(webhooksAttr))
528533
return;
529534
var webhooks = Arrays.stream(webhooksAttr).map(Webhooks::value).flatMap(Arrays::stream).toArray(Webhook[]::new);
530535
Arrays.stream(webhooks).forEach(webhook -> {

springdoc-openapi-starter-common/src/main/java/org/springdoc/core/service/OpenAPIService.java

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
* The type Open api builder.
105105
*
106106
* @author bnasslahsen
107+
* @author zdary
107108
*/
108109
public class OpenAPIService implements ApplicationContextAware {
109110

@@ -538,63 +539,72 @@ private Optional<OpenAPIDefinition> getOpenAPIDefinition() {
538539
}
539540

540541

541-
/**
542-
* Get webhooks webhooks [ ].
543-
*
544-
* @return the webhooks [ ]
545-
*/
546-
public Webhooks[] getWebhooks() {
547-
List<Webhooks> allWebhooks = new ArrayList<>();
548-
549-
// First: scan Spring-managed beans
550-
Map<String, Object> beans = context.getBeansWithAnnotation(Webhooks.class);
551-
552-
for (Object bean : beans.values()) {
553-
Class<?> beanClass = bean.getClass();
554-
555-
// Collect @Webhooks or @Webhook on class level
556-
collectWebhooksFromElement(beanClass, allWebhooks);
542+
/**
543+
* Gets webhooks from given classes.
544+
*
545+
* @param classes Array of classes to scan for webhooks.
546+
* @return An array of {@link Webhooks} annotations found in the given classes.
547+
*/
548+
public Webhooks[] getWebhooks(Class<?>[] classes) {
549+
List<Webhooks> allWebhooks = new ArrayList<>();
550+
551+
for (Class<?> clazz : classes) {
552+
// Class-level annotations
553+
collectWebhooksFromElement(clazz, allWebhooks);
554+
555+
// Method-level annotations
556+
for (Method method : clazz.getDeclaredMethods()) {
557+
collectWebhooksFromElement(method, allWebhooks);
558+
}
559+
}
560+
561+
return allWebhooks.toArray(new Webhooks[0]);
562+
}
563+
564+
565+
/**
566+
* Retrieves all classes related to webhooks.
567+
* This method scans for classes annotated with {@link Webhooks} or {@link Webhook},
568+
* first checking Spring-managed beans and then falling back to classpath scanning
569+
* if no annotated beans are found.
570+
*
571+
* @return An array of classes related to webhooks.
572+
*/
573+
public Class<?>[] getWebhooksClasses() {
574+
Set<Class<?>> allWebhookClassesToScan = new HashSet<>();
575+
576+
// First: scan Spring-managed beans
577+
Map<String, Object> beans = context.getBeansWithAnnotation(Webhooks.class);
578+
579+
for (Object bean : beans.values()) {
580+
Class<?> beanClass = bean.getClass();
581+
allWebhookClassesToScan.add(beanClass);
582+
}
583+
584+
// Fallback: classpath scanning
585+
ClassPathScanningCandidateComponentProvider scanner =
586+
new ClassPathScanningCandidateComponentProvider(false);
587+
scanner.addIncludeFilter(new AnnotationTypeFilter(Webhooks.class));
588+
scanner.addIncludeFilter(new AnnotationTypeFilter(Webhook.class));
589+
590+
if (AutoConfigurationPackages.has(context)) {
591+
for (String basePackage : AutoConfigurationPackages.get(context)) {
592+
Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);
593+
for (BeanDefinition bd : candidates) {
594+
try {
595+
Class<?> clazz = Class.forName(bd.getBeanClassName());
596+
allWebhookClassesToScan.add(clazz);
597+
}
598+
catch (ClassNotFoundException e) {
599+
LOGGER.error("Class not found in classpath: {}", e.getMessage());
600+
}
601+
}
602+
}
603+
}
604+
605+
return allWebhookClassesToScan.toArray(new Class<?>[0]);
606+
}
557607

558-
// Collect from methods
559-
for (Method method : beanClass.getDeclaredMethods()) {
560-
collectWebhooksFromElement(method, allWebhooks);
561-
}
562-
}
563-
564-
// Fallback: classpath scanning if nothing found
565-
if (allWebhooks.isEmpty()) {
566-
ClassPathScanningCandidateComponentProvider scanner =
567-
new ClassPathScanningCandidateComponentProvider(false);
568-
scanner.addIncludeFilter(new AnnotationTypeFilter(Webhooks.class));
569-
scanner.addIncludeFilter(new AnnotationTypeFilter(Webhook.class));
570-
571-
if (AutoConfigurationPackages.has(context)) {
572-
for (String basePackage : AutoConfigurationPackages.get(context)) {
573-
Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);
574-
575-
for (BeanDefinition bd : candidates) {
576-
try {
577-
Class<?> clazz = Class.forName(bd.getBeanClassName());
578-
579-
// Class-level annotations
580-
collectWebhooksFromElement(clazz, allWebhooks);
581-
582-
// Method-level annotations
583-
for (Method method : clazz.getDeclaredMethods()) {
584-
collectWebhooksFromElement(method, allWebhooks);
585-
}
586-
587-
}
588-
catch (ClassNotFoundException e) {
589-
LOGGER.error("Class not found in classpath: {}", e.getMessage());
590-
}
591-
}
592-
}
593-
}
594-
}
595-
596-
return allWebhooks.toArray(new Webhooks[0]);
597-
}
598608

599609
/**
600610
* Collect webhooks from element.

springdoc-openapi-starter-common/src/test/java/org/springdoc/api/AbstractOpenApiResourceTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ public void setUp() {
125125

126126
when(openAPIService.build(any())).thenReturn(openAPI);
127127
when(openAPIService.getContext()).thenReturn(context);
128-
doAnswer(new CallsRealMethods()).when(openAPIService).setServersPresent(false);
128+
when(openAPIService.getWebhooksClasses()).thenReturn(new Class<?>[0]);
129+
doAnswer(new CallsRealMethods()).when(openAPIService).setServersPresent(false);
129130

130131
when(openAPIBuilderObjectFactory.getObject()).thenReturn(openAPIService);
131132
when(springDocProviders.jsonMapper()).thenReturn(Json.mapper());
@@ -295,4 +296,4 @@ private static class EmptyPathsOpenApiResource extends AbstractOpenApiResource {
295296
public void getPaths(Map<String, Object> findRestControllers, Locale locale, OpenAPI openAPI) {
296297
}
297298
}
298-
}
299+
}

0 commit comments

Comments
 (0)