Skip to content

Commit

Permalink
feat(core): find channels defined via bean configuration
Browse files Browse the repository at this point in the history
add SpringwolfClassScanner
  • Loading branch information
timonback committed Nov 29, 2023
1 parent 691d929 commit 074c769
Show file tree
Hide file tree
Showing 16 changed files with 179 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ConfigurationClassScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.SpringwolfClassScanner;
import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
import io.github.stavshamir.springwolf.schemas.SchemasService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
Expand Down Expand Up @@ -44,9 +45,8 @@ public ComponentClassScanner componentClassScanner(

@Bean
@ConditionalOnMissingBean
public ConfigurationClassScanner configurationClassScanner(
AsyncApiDocketService asyncApiDocketService, Environment environment) {
return new ConfigurationClassScanner(asyncApiDocketService, environment);
public ConfigurationClassScanner configurationClassScanner(ComponentClassScanner componentClassScanner) {
return new ConfigurationClassScanner(componentClassScanner);
}

@Bean
Expand All @@ -55,6 +55,13 @@ public BeanMethodsScanner beanMethodsScanner(ConfigurationClassScanner configura
return new DefaultBeanMethodsScanner(configurationClassScanner);
}

@Bean
@ConditionalOnMissingBean
public SpringwolfClassScanner springwolfClassScanner(
ComponentClassScanner componentClassScanner, BeanMethodsScanner beanMethodsScanner) {
return new SpringwolfClassScanner(componentClassScanner, beanMethodsScanner);
}

@Bean
@ConditionalOnProperty(name = SPRINGWOLF_SCANNER_CONSUMER_DATA_ENABLED, havingValue = "true", matchIfMissing = true)
@Order(value = ChannelPriority.MANUAL_DEFINED)
Expand All @@ -78,14 +85,14 @@ public ProducerOperationDataScanner producerOperationDataScanner(
matchIfMissing = true)
@Order(value = ChannelPriority.ASYNC_ANNOTATION)
public AsyncListenerAnnotationScanner asyncListenerAnnotationScanner(
ComponentClassScanner componentClassScanner,
SpringwolfClassScanner springwolfClassScanner,
SchemasService schemasService,
AsyncApiDocketService asyncApiDocketService,
PayloadClassExtractor payloadClassExtractor,
List<OperationBindingProcessor> operationBindingProcessors,
List<MessageBindingProcessor> messageBindingProcessors) {
return new AsyncListenerAnnotationScanner(
componentClassScanner,
springwolfClassScanner,
schemasService,
asyncApiDocketService,
payloadClassExtractor,
Expand All @@ -100,14 +107,14 @@ public AsyncListenerAnnotationScanner asyncListenerAnnotationScanner(
matchIfMissing = true)
@Order(value = ChannelPriority.ASYNC_ANNOTATION)
public AsyncPublisherAnnotationScanner asyncPublisherAnnotationScanner(
ComponentClassScanner componentClassScanner,
SpringwolfClassScanner springwolfClassScanner,
SchemasService schemasService,
AsyncApiDocketService asyncApiDocketService,
PayloadClassExtractor payloadClassExtractor,
List<OperationBindingProcessor> operationBindingProcessors,
List<MessageBindingProcessor> messageBindingProcessors) {
return new AsyncPublisherAnnotationScanner(
componentClassScanner,
springwolfClassScanner,
schemasService,
asyncApiDocketService,
payloadClassExtractor,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.scanners.beans;

import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.AnnotationUtil;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ConfigurationClassScanner;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
Expand All @@ -9,7 +10,6 @@
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toSet;

Expand All @@ -20,13 +20,11 @@ public class DefaultBeanMethodsScanner implements BeanMethodsScanner {

@Override
public Set<Method> getBeanMethods() {
Set<Class<?>> configurationClasses = configurationClassScanner.scan();

Stream<Method> methods = configurationClasses.stream()
return configurationClassScanner.scan().stream()
.map(Class::getDeclaredMethods)
.map(Arrays::asList)
.flatMap(List::stream);

return methods.filter(method -> method.isAnnotationPresent(Bean.class)).collect(toSet());
.flatMap(List::stream)
.filter(method -> AnnotationUtil.findAnnotation(Bean.class, method) != null)
.collect(toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.AnnotationUtil;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.AbstractOperationDataScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.ConsumerData;
import io.github.stavshamir.springwolf.asyncapi.types.OperationData;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
Expand All @@ -30,7 +30,7 @@
@RequiredArgsConstructor
public class AsyncListenerAnnotationScanner extends AbstractOperationDataScanner implements EmbeddedValueResolverAware {
private StringValueResolver resolver;
private final ComponentClassScanner componentClassScanner;
private final ClassScanner classScanner;
private final SchemasService schemasService;
private final AsyncApiDocketService asyncApiDocketService;

Expand All @@ -56,7 +56,7 @@ protected AsyncApiDocketService getAsyncApiDocketService() {

@Override
protected List<OperationData> getOperationData() {
return componentClassScanner.scan().stream()
return classScanner.scan().stream()
.flatMap(this::getAnnotatedMethods)
.flatMap(this::toOperationData)
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.AnnotationUtil;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.operationdata.AbstractOperationDataScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.OperationData;
import io.github.stavshamir.springwolf.asyncapi.types.ProducerData;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
Expand All @@ -31,7 +31,7 @@
public class AsyncPublisherAnnotationScanner extends AbstractOperationDataScanner
implements EmbeddedValueResolverAware {
private StringValueResolver resolver;
private final ComponentClassScanner componentClassScanner;
private final ClassScanner classScanner;
private final SchemasService schemasService;
private final AsyncApiDocketService asyncApiDocketService;

Expand All @@ -57,7 +57,7 @@ protected AsyncApiDocketService getAsyncApiDocketService() {

@Override
protected List<OperationData> getOperationData() {
return componentClassScanner.scan().stream()
return classScanner.scan().stream()
.flatMap(this::getAnnotatedMethods)
.flatMap(this::toOperationData)
.toList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,13 @@

@Slf4j
@RequiredArgsConstructor
public abstract class AbstractAnnotatedClassScanner<T extends Annotation> implements ClassScanner {
public class AnnotationClassScanner<T extends Annotation> implements ClassScanner {

private final Class<T> annotation;
private final AsyncApiDocketService asyncApiDocketService;

private final Environment environment;

/**
* @return The class object of the annotation to scan.
*/
protected abstract Class<T> getAnnotationClass();

@Override
public Set<Class<?>> scan() {
String basePackage = asyncApiDocketService.getAsyncApiDocket().getBasePackage();
Expand All @@ -39,9 +35,9 @@ public Set<Class<?>> scan() {
ClassPathScanningCandidateComponentProvider provider =
new ClassPathScanningCandidateComponentProvider(false, environment);

provider.addIncludeFilter(new AnnotationTypeFilter(getAnnotationClass()));
provider.addIncludeFilter(new AnnotationTypeFilter(annotation));

log.debug("Scanning for {} classes in {}", getAnnotationClass().getSimpleName(), basePackage);
log.debug("Scanning for {} classes in {}", annotation.getSimpleName(), basePackage);
return provider.findCandidateComponents(basePackage).stream()
.map(BeanDefinition::getBeanClassName)
.map(this::getClass)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,18 @@
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

public class ComponentClassScanner extends AbstractAnnotatedClassScanner<Component> implements ClassScanner {
import java.util.Set;

public class ComponentClassScanner implements ClassScanner {

private final AnnotationClassScanner<Component> scanner;

public ComponentClassScanner(AsyncApiDocketService asyncApiDocketService, Environment environment) {
super(asyncApiDocketService, environment);
this.scanner = new AnnotationClassScanner<>(Component.class, asyncApiDocketService, environment);
}

@Override
protected Class<Component> getAnnotationClass() {
return Component.class;
public Set<Class<?>> scan() {
return scanner.scan();
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.scanners.classes;

import io.github.stavshamir.springwolf.configuration.AsyncApiDocketService;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.annotation.AnnotationUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

public class ConfigurationClassScanner extends AbstractAnnotatedClassScanner<Configuration> implements ClassScanner {
import java.util.Set;
import java.util.stream.Collectors;

public ConfigurationClassScanner(AsyncApiDocketService asyncApiDocketService, Environment environment) {
super(asyncApiDocketService, environment);
}
@RequiredArgsConstructor
public class ConfigurationClassScanner implements ClassScanner {

private final ComponentClassScanner scanner;

@Override
protected Class<Configuration> getAnnotationClass() {
return Configuration.class;
public Set<Class<?>> scan() {
return scanner.scan().stream()
// All Configurations are also Components
.filter((cls) -> AnnotationUtil.findAnnotation(Configuration.class, cls) != null)
.collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.stavshamir.springwolf.asyncapi.scanners.classes;

import io.github.stavshamir.springwolf.asyncapi.scanners.beans.BeanMethodsScanner;
import lombok.RequiredArgsConstructor;

import java.lang.reflect.Method;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@RequiredArgsConstructor
public class SpringwolfClassScanner implements ClassScanner {

private final ComponentClassScanner scanner;
private final BeanMethodsScanner beanMethodsScanner;

@Override
public Set<Class<?>> scan() {
Stream<Class<?>> components = scanner.scan().stream();
Stream<Class<?>> configurationBeans =
beanMethodsScanner.getBeanMethods().stream().map(Method::getReturnType);

return Stream.concat(components, configurationBeans).collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.asyncapi.v2._6_0.model.server.Server;
import io.github.stavshamir.springwolf.asyncapi.scanners.bindings.processor.TestOperationBindingProcessor;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
Expand Down Expand Up @@ -70,14 +70,14 @@ class AsyncListenerAnnotationScannerIntegrationTest {
private AsyncListenerAnnotationScanner channelScanner;

@MockBean
private ComponentClassScanner componentClassScanner;
private ClassScanner classScanner;

@MockBean
private AsyncApiDocketService asyncApiDocketService;

private void setClassToScan(Class<?> classToScan) {
Set<Class<?>> classesToScan = singleton(classToScan);
when(componentClassScanner.scan()).thenReturn(classesToScan);
when(classScanner.scan()).thenReturn(classesToScan);
}

@BeforeEach
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.asyncapi.v2._6_0.model.channel.operation.Operation;
import io.github.stavshamir.springwolf.asyncapi.scanners.bindings.processor.TestOperationBindingProcessor;
import io.github.stavshamir.springwolf.asyncapi.scanners.channels.payload.PayloadClassExtractor;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ComponentClassScanner;
import io.github.stavshamir.springwolf.asyncapi.scanners.classes.ClassScanner;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.Message;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.PayloadReference;
import io.github.stavshamir.springwolf.asyncapi.types.channel.operation.message.header.AsyncHeaders;
Expand Down Expand Up @@ -57,14 +57,14 @@ class AsyncPublisherAnnotationScannerIntegrationTest {
private AsyncPublisherAnnotationScanner channelScanner;

@MockBean
private ComponentClassScanner componentClassScanner;
private ClassScanner classScanner;

@MockBean
private AsyncApiDocketService asyncApiDocketService;

private void setClassToScan(Class<?> classToScan) {
Set<Class<?>> classesToScan = singleton(classToScan);
when(componentClassScanner.scan()).thenReturn(classesToScan);
when(classScanner.scan()).thenReturn(classesToScan);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,13 @@ void setUp() {

@Test
void getComponents() {
StandardEnvironment environment = (StandardEnvironment) beanFactory.getBean(Environment.class);
environment.getSystemProperties().put(TestConditionalComponent.CONDITIONAL_PROPERTY, false);

Set<Class<?>> components = componentsScanner.scan();

assertThat(components)
.doesNotContain(TestBeanConfiguration.TestBean.class)
.contains(TestComponent.class)
.doesNotContain(TestConditionalComponent.class)
.doesNotContain(TestOtherConditionalComponent.class);
Expand All @@ -69,6 +73,7 @@ void getComponentsIncludesConditional() {
Set<Class<?>> components = componentsScanner.scan();

assertThat(components)
.doesNotContain(TestBeanConfiguration.TestBean.class)
.contains(TestComponent.class)
.contains(TestConditionalComponent.class)
.doesNotContain(TestOtherConditionalComponent.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import static org.mockito.Mockito.when;

@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = {ConfigurationClassScanner.class})
@ContextConfiguration(classes = {ConfigurationClassScanner.class, ComponentClassScanner.class})
class ConfigurationClassScannerIntegrationTest {

@MockBean
Expand Down
Loading

0 comments on commit 074c769

Please sign in to comment.