Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,6 +22,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
Expand Down Expand Up @@ -105,4 +106,17 @@
*/
Filter[] excludeFilters() default { };


/**
* The {@link BeanNameGenerator} class to be used for naming detected Spring Integration components.
* <p>The default value of the {@link BeanNameGenerator} interface itself indicates
* that the scanner used to process this {@link IntegrationComponentScan} annotation should
* use its inherited bean name generator, e.g. the default
* {@link org.springframework.context.annotation.AnnotationBeanNameGenerator}
* or any custom instance supplied to the application context at bootstrap time.
* @since 6.0
* @see org.springframework.context.annotation.ComponentScan#nameGenerator()
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,13 +23,15 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

/**
* Stereotype annotation indicating that a class is capable of serving as a
* Message Endpoint.
*
* @author Mark Fisher
* @author Artem Bilan
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
Expand All @@ -41,9 +43,9 @@
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
*
* @return the suggested component name, if any
*/
@AliasFor(annotation = Component.class)
String value() default "";

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2021 the original author or authors.
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -21,12 +21,12 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.stereotype.Indexed;
import org.springframework.core.annotation.AliasFor;

/**
* A stereotype annotation to provide an Integration Messaging Gateway Proxy
* ({@code <gateway/>}) as an abstraction over the messaging API. The target
* application's business logic may be completely unaware of the Spring Integration
* as an abstraction over the messaging API. The target application's
* business logic may be completely unaware of the Spring Integration
* API, with the code interacting only via the interface.
* <p>
* Important: The {@link IntegrationComponentScan} annotation is required along with
Expand All @@ -41,17 +41,28 @@
* @since 4.0
*
* @see IntegrationComponentScan
* @see MessageEndpoint
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Indexed
@MessageEndpoint
public @interface MessagingGateway {

/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
* @since 6.0
*/
@AliasFor(annotation = MessageEndpoint.class)
String value() default "";

/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
* @return the suggested component name, if any
*/
@AliasFor(annotation = MessageEndpoint.class, attribute = "value")
String name() default "";

/**
Expand Down Expand Up @@ -90,7 +101,7 @@

/**
* Allows to specify how long this gateway will wait for the reply {@code Message}
* before returning. By default it will wait indefinitely. {@code null} is returned if
* before returning. By default, it will wait indefinitely. {@code null} is returned if
* the gateway times out. Value is specified in milliseconds; it can be a simple long
* value or a SpEL expression; array variable #args is available.
* @return the suggested timeout in milliseconds, if any
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.gateway.AnnotationGatewayProxyFactoryBean;
Expand Down Expand Up @@ -54,20 +56,23 @@ public void setApplicationContext(ApplicationContext applicationContext) throws

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if (beanClass.isInterface()
&& AnnotatedElementUtils.hasAnnotation(beanClass, MessagingGateway.class)
&& this.registry.getBeanDefinition(beanName) instanceof AnnotatedGenericBeanDefinition) {
if (beanClass.isInterface() && AnnotatedElementUtils.hasAnnotation(beanClass, MessagingGateway.class)) {
BeanDefinition beanDefinition = this.registry.getBeanDefinition(beanName);
if (beanDefinition instanceof AnnotatedGenericBeanDefinition
|| beanDefinition instanceof ScannedGenericBeanDefinition) {

AnnotationGatewayProxyFactoryBean<?> gatewayProxyFactoryBean =
new AnnotationGatewayProxyFactoryBean<>(beanClass);
gatewayProxyFactoryBean.setApplicationContext(this.applicationContext);
gatewayProxyFactoryBean.setBeanFactory(this.applicationContext.getAutowireCapableBeanFactory());
ClassLoader classLoader = this.applicationContext.getClassLoader();
if (classLoader != null) {
gatewayProxyFactoryBean.setBeanClassLoader(classLoader);
AnnotationGatewayProxyFactoryBean<?> gatewayProxyFactoryBean =
new AnnotationGatewayProxyFactoryBean<>(beanClass);
gatewayProxyFactoryBean.setApplicationContext(this.applicationContext);
gatewayProxyFactoryBean.setBeanFactory(this.applicationContext.getAutowireCapableBeanFactory());
ClassLoader classLoader = this.applicationContext.getClassLoader();
if (classLoader != null) {
gatewayProxyFactoryBean.setBeanClassLoader(classLoader);
}
gatewayProxyFactoryBean.setBeanName(beanName);
gatewayProxyFactoryBean.afterPropertiesSet();
return gatewayProxyFactoryBean;
}
gatewayProxyFactoryBean.setBeanName(beanName);
return gatewayProxyFactoryBean;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2019 the original author or authors.
* Copyright 2014-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,10 +20,8 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

Expand All @@ -33,11 +31,12 @@
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
Expand Down Expand Up @@ -67,15 +66,14 @@
public class IntegrationComponentScanRegistrar implements ImportBeanDefinitionRegistrar,
ResourceLoaderAware, EnvironmentAware {

private final Map<TypeFilter, ImportBeanDefinitionRegistrar> componentRegistrars = new HashMap<>();
private final List<TypeFilter> defaultFilters = new ArrayList<>();

private ResourceLoader resourceLoader;

private Environment environment;

public IntegrationComponentScanRegistrar() {
this.componentRegistrars.put(new AnnotationTypeFilter(MessagingGateway.class, true),
new MessagingGatewayRegistrar());
this.defaultFilters.add(new AnnotationTypeFilter(MessagingGateway.class, true));
}

@Override
Expand All @@ -90,84 +88,75 @@ public void setEnvironment(Environment environment) {

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Map<String, Object> componentScan =
importingClassMetadata.getAnnotationAttributes(IntegrationComponentScan.class.getName());
AnnotationAttributes componentScan =
AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(IntegrationComponentScan.class.getName()));

Collection<String> basePackages = getBasePackages(importingClassMetadata, registry);
Collection<String> basePackages = getBasePackages(componentScan, registry);

if (basePackages.isEmpty()) {
basePackages = Collections.singleton(ClassUtils.getPackageName(importingClassMetadata.getClassName()));
}

ClassPathScanningCandidateComponentProvider scanner =
new ClassPathScanningCandidateComponentProvider(false, this.environment) {
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, false) {

@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isIndependent()
&& !beanDefinition.getMetadata().isAnnotation();
}

@Override
protected BeanDefinitionRegistry getRegistry() {
return registry;
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return beanDefinition.getMetadata().isIndependent()
&& !beanDefinition.getMetadata().isAnnotation();
}

};
};

filter(registry, componentScan, scanner); // NOSONAR - never null

scanner.setResourceLoader(this.resourceLoader);
scanner.setEnvironment(this.environment);

for (String basePackage : basePackages) {
Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition) {
for (ImportBeanDefinitionRegistrar registrar : this.componentRegistrars.values()) {
registrar.registerBeanDefinitions(((AnnotatedBeanDefinition) candidateComponent).getMetadata(),
registry);
}
}
}
BeanNameGenerator beanNameGenerator = IntegrationConfigUtils.annotationBeanNameGenerator(registry);

Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
if (!(BeanNameGenerator.class == generatorClass)) {
beanNameGenerator = BeanUtils.instantiateClass(generatorClass);
}

scanner.setBeanNameGenerator(beanNameGenerator);
scanner.scan(basePackages.toArray(String[]::new));
}

private void filter(BeanDefinitionRegistry registry, Map<String, Object> componentScan,
private void filter(BeanDefinitionRegistry registry, AnnotationAttributes componentScan,
ClassPathScanningCandidateComponentProvider scanner) {

if ((boolean) componentScan.get("useDefaultFilters")) { // NOSONAR - never null
for (TypeFilter typeFilter : this.componentRegistrars.keySet()) {
if (componentScan.getBoolean("useDefaultFilters")) { // NOSONAR - never null
for (TypeFilter typeFilter : this.defaultFilters) {
scanner.addIncludeFilter(typeFilter);
}
}

for (AnnotationAttributes filter : (AnnotationAttributes[]) componentScan.get("includeFilters")) {
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter, registry)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : (AnnotationAttributes[]) componentScan.get("excludeFilters")) {
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter, registry)) {
scanner.addExcludeFilter(typeFilter);
}
}
}

protected Collection<String> getBasePackages(AnnotationMetadata importingClassMetadata,
protected Collection<String> getBasePackages(AnnotationAttributes componentScan,
@SuppressWarnings("unused") BeanDefinitionRegistry registry) {

Map<String, Object> componentScan =
importingClassMetadata.getAnnotationAttributes(IntegrationComponentScan.class.getName());

Set<String> basePackages = new HashSet<>();

for (String pkg : (String[]) componentScan.get("value")) { // NOSONAR - never null
for (String pkg : componentScan.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}

for (Class<?> clazz : (Class<?>[]) componentScan.get("basePackageClasses")) {
for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}

Expand All @@ -180,38 +169,33 @@ private List<TypeFilter> typeFiltersFor(AnnotationAttributes filter, BeanDefinit

for (Class<?> filterClass : filter.getClassArray("classes")) {
switch (filterType) {
case ANNOTATION:
case ANNOTATION -> {
Assert.isAssignable(Annotation.class, filterClass,
"An error occurred while processing a @IntegrationComponentScan ANNOTATION type filter: ");
@SuppressWarnings("unchecked")
Class<Annotation> annotationType = (Class<Annotation>) filterClass;
typeFilters.add(new AnnotationTypeFilter(annotationType));
break;
case ASSIGNABLE_TYPE:
typeFilters.add(new AssignableTypeFilter(filterClass));
break;
case CUSTOM:
}
case ASSIGNABLE_TYPE -> typeFilters.add(new AssignableTypeFilter(filterClass));
case CUSTOM -> {
Assert.isAssignable(TypeFilter.class, filterClass,
"An error occurred while processing a @IntegrationComponentScan CUSTOM type filter: ");
TypeFilter typeFilter = BeanUtils.instantiateClass(filterClass, TypeFilter.class);
invokeAwareMethods(filter, this.environment, this.resourceLoader, registry);
typeFilters.add(typeFilter);
break;
default:
throw new IllegalArgumentException("Filter type not supported with Class value: " + filterType);
}
default -> throw new IllegalArgumentException("Filter type not supported with Class value: " +
filterType);
}
}

for (String expression : filter.getStringArray("pattern")) {
switch (filterType) {
case ASPECTJ:
typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader()));
break;
case REGEX:
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
break;
default:
throw new IllegalArgumentException("Filter type not supported with String pattern: " + filterType);
case ASPECTJ ->
typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader.getClassLoader()));
case REGEX -> typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
default -> throw new IllegalArgumentException("Filter type not supported with String pattern: "
+ filterType);
}
}

Expand Down
Loading