GH-2708: Make messaging annotations as repeatable
Fixes https://github.com/spring-projects/spring-integration/issues/2708 There are some requests to use the same service method for different input channels * Make all the messaging annotations as `@Repeatable` with their respective container annotations * Modify `MessagingAnnotationPostProcessor` logic to deal with the mentioned repeatable requirements
This commit is contained in:
committed by
Gary Russell
parent
f54d4b3d75
commit
97ab596841
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -39,6 +40,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(Aggregators.class)
|
||||
public @interface Aggregator {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link Aggregator} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Aggregators {
|
||||
|
||||
Aggregator[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -45,6 +46,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(BridgeFromRepeatable.class)
|
||||
public @interface BridgeFrom {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link BridgeFrom} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BridgeFromRepeatable {
|
||||
|
||||
BridgeFrom[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -50,6 +51,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(BridgeToRepeatable.class)
|
||||
public @interface BridgeTo {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link BridgeTo} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface BridgeToRepeatable {
|
||||
|
||||
BridgeTo[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -47,6 +48,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(Filters.class)
|
||||
public @interface Filter {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link Filter} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Filters {
|
||||
|
||||
Filter[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -53,6 +54,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(InboundChannelAdapters.class)
|
||||
public @interface InboundChannelAdapter {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link InboundChannelAdapter} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InboundChannelAdapters {
|
||||
|
||||
InboundChannelAdapter[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -50,6 +51,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(Routers.class)
|
||||
public @interface Router {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link Router} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Routers {
|
||||
|
||||
Router[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(ServiceActivators.class)
|
||||
public @interface ServiceActivator {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link ServiceActivator} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ServiceActivators {
|
||||
|
||||
ServiceActivator[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(Splitters.class)
|
||||
public @interface Splitter {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link Splitter} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Splitters {
|
||||
|
||||
Splitter[] value();
|
||||
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.messaging.handler.annotation.ValueConstants;
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Repeatable(Transformers.class)
|
||||
public @interface Transformer {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* The repeatable container for {@link Transformer} annotations.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Transformers {
|
||||
|
||||
Transformer[] value();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
@@ -25,7 +25,6 @@ import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@@ -42,13 +41,13 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.integration.annotation.Aggregator;
|
||||
import org.springframework.integration.annotation.BridgeFrom;
|
||||
import org.springframework.integration.annotation.BridgeTo;
|
||||
import org.springframework.integration.annotation.EndpointId;
|
||||
import org.springframework.integration.annotation.Filter;
|
||||
import org.springframework.integration.annotation.InboundChannelAdapter;
|
||||
import org.springframework.integration.annotation.Role;
|
||||
@@ -161,28 +160,34 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
}
|
||||
|
||||
private void doWithMethod(Method method, Object bean, String beanName, Class<?> beanClass) {
|
||||
Map<Class<? extends Annotation>, List<Annotation>> annotationChains = new HashMap<>();
|
||||
for (Class<? extends Annotation> annotationType :
|
||||
this.postProcessors.keySet()) {
|
||||
if (AnnotatedElementUtils.isAnnotated(method, annotationType.getName())) {
|
||||
List<Annotation> annotationChain = getAnnotationChain(method, annotationType);
|
||||
if (annotationChain.size() > 0) {
|
||||
annotationChains.put(annotationType, annotationChain);
|
||||
}
|
||||
}
|
||||
MergedAnnotations mergedAnnotations =
|
||||
MergedAnnotations.search(MergedAnnotations.SearchStrategy.DIRECT)
|
||||
.from(method);
|
||||
|
||||
List<MessagingMetaAnnotation> messagingAnnotations = new ArrayList<>();
|
||||
|
||||
for (Class<? extends Annotation> annotationType : this.postProcessors.keySet()) {
|
||||
mergedAnnotations.stream()
|
||||
.filter((ann) -> ann.getType().equals(annotationType))
|
||||
.map(MergedAnnotation::getRoot)
|
||||
.map(MergedAnnotation::synthesize)
|
||||
.map((ann) -> new MessagingMetaAnnotation(ann, annotationType))
|
||||
.forEach(messagingAnnotations::add);
|
||||
}
|
||||
if (StringUtils.hasText(MessagingAnnotationUtils.endpointIdValue(method))
|
||||
&& annotationChains.keySet().size() > 1) {
|
||||
if (mergedAnnotations.get(EndpointId.class, (ann) -> ann.hasNonDefaultValue("value")).isPresent()
|
||||
&& messagingAnnotations.size() > 1) {
|
||||
|
||||
throw new IllegalStateException("@EndpointId on " + method.toGenericString()
|
||||
+ " can only have one EIP annotation, found: " + annotationChains.keySet().size());
|
||||
}
|
||||
for (Entry<Class<? extends Annotation>, List<Annotation>> entry : annotationChains.entrySet()) {
|
||||
Class<? extends Annotation> annotationType = entry.getKey();
|
||||
List<Annotation> annotations = entry.getValue();
|
||||
processAnnotationTypeOnMethod(bean, beanName, method, annotationType, annotations);
|
||||
+ " can only have one EIP annotation, found: " + messagingAnnotations.size());
|
||||
}
|
||||
|
||||
if (annotationChains.size() == 0) {
|
||||
for (MessagingMetaAnnotation messagingAnnotation : messagingAnnotations) {
|
||||
Class<? extends Annotation> annotationType = messagingAnnotation.messagingAnnotationType;
|
||||
List<Annotation> annotationChain = getAnnotationChain(messagingAnnotation.annotation, annotationType);
|
||||
processAnnotationTypeOnMethod(bean, beanName, method, annotationType, annotationChain);
|
||||
}
|
||||
|
||||
if (messagingAnnotations.size() == 0) {
|
||||
this.noAnnotationsCache.add(beanClass);
|
||||
}
|
||||
}
|
||||
@@ -226,10 +231,8 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
Object result = postProcessor.postProcess(bean, beanName, targetMethod, annotations);
|
||||
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
|
||||
BeanDefinitionRegistry definitionRegistry = (BeanDefinitionRegistry) beanFactory;
|
||||
if (result instanceof AbstractEndpoint) {
|
||||
AbstractEndpoint endpoint = (AbstractEndpoint) result;
|
||||
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup",
|
||||
String.class);
|
||||
if (result instanceof AbstractEndpoint endpoint) {
|
||||
String autoStartup = MessagingAnnotationUtils.resolveAttribute(annotations, "autoStartup", String.class);
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
autoStartup = beanFactory.resolveEmbeddedValue(autoStartup);
|
||||
if (StringUtils.hasText(autoStartup)) {
|
||||
@@ -259,20 +262,19 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
}
|
||||
|
||||
/**
|
||||
* @param method the method.
|
||||
* @param messagingAnnotation the {@link Annotation} to take a chain for its meta-annotations.
|
||||
* @param annotationType the annotation type.
|
||||
* @return the hierarchical list of annotations in top-bottom order.
|
||||
*/
|
||||
protected List<Annotation> getAnnotationChain(Method method, Class<? extends Annotation> annotationType) {
|
||||
protected List<Annotation> getAnnotationChain(Annotation messagingAnnotation,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
List<Annotation> annotationChain = new LinkedList<>();
|
||||
Set<Annotation> visited = new HashSet<>();
|
||||
|
||||
for (MergedAnnotation<Annotation> mergedAnnotation : MergedAnnotations.from(method)) {
|
||||
recursiveFindAnnotation(annotationType, mergedAnnotation.synthesize(), annotationChain, visited);
|
||||
if (annotationChain.size() > 0) {
|
||||
Collections.reverse(annotationChain);
|
||||
return annotationChain;
|
||||
}
|
||||
recursiveFindAnnotation(annotationType, messagingAnnotation, annotationChain, visited);
|
||||
if (annotationChain.size() > 0) {
|
||||
Collections.reverse(annotationChain);
|
||||
}
|
||||
|
||||
return annotationChain;
|
||||
@@ -280,6 +282,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
|
||||
protected boolean recursiveFindAnnotation(Class<? extends Annotation> annotationType, Annotation ann,
|
||||
List<Annotation> annotationChain, Set<Annotation> visited) {
|
||||
|
||||
if (ann.annotationType().equals(annotationType)) {
|
||||
annotationChain.add(ann);
|
||||
return true;
|
||||
@@ -299,6 +302,7 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
|
||||
protected String generateBeanName(String originalBeanName, Method method,
|
||||
Class<? extends Annotation> annotationType) {
|
||||
|
||||
String name = MessagingAnnotationUtils.endpointIdValue(method);
|
||||
if (!StringUtils.hasText(name)) {
|
||||
String baseName = originalBeanName + "." + method.getName() + "."
|
||||
@@ -316,4 +320,8 @@ public class MessagingAnnotationPostProcessor implements BeanPostProcessor, Bean
|
||||
return this.postProcessors;
|
||||
}
|
||||
|
||||
private record MessagingMetaAnnotation(Annotation annotation, Class<? extends Annotation> messagingAnnotationType) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -298,6 +298,12 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
inputChannel.send(new GenericMessage<>("foo"));
|
||||
Message<?> reply = outputChannel.receive(0);
|
||||
assertThat(reply.getPayload()).isEqualTo("FOO");
|
||||
|
||||
MessageChannel inputChannel2 = context.getBean("inputChannel2", MessageChannel.class);
|
||||
inputChannel2.send(new GenericMessage<>("test2"));
|
||||
reply = outputChannel.receive(0);
|
||||
assertThat(reply.getPayload()).isEqualTo("TEST2");
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
@@ -386,6 +392,7 @@ public class MessagingAnnotationPostProcessorTests {
|
||||
public static class TransformerAnnotationTestBean {
|
||||
|
||||
@Transformer(inputChannel = "inputChannel", outputChannel = "outputChannel")
|
||||
@Transformer(inputChannel = "inputChannel2", outputChannel = "outputChannel")
|
||||
public String transformBefore(String input) {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
@@ -385,9 +385,9 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
|
||||
|
||||
@Bean
|
||||
@ServiceActivator(inputChannel = "skippedChannel")
|
||||
@Splitter(inputChannel = "skippedChannel2")
|
||||
@ServiceActivator(inputChannel = "skippedChannel2")
|
||||
@Router(inputChannel = "skippedChannel3")
|
||||
@Transformer(inputChannel = "skippedChannel4")
|
||||
@Filter(inputChannel = "skippedChannel4")
|
||||
@Filter(inputChannel = "skippedChannel5")
|
||||
@Profile("foo")
|
||||
public MessageHandler skippedMessageHandler() {
|
||||
@@ -396,6 +396,7 @@ public class MessagingAnnotationsWithBeanAnnotationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@BridgeFrom("skippedChannel5")
|
||||
@BridgeFrom("skippedChannel6")
|
||||
@Profile("foo")
|
||||
public MessageChannel skippedChannel1() {
|
||||
|
||||
@@ -250,6 +250,9 @@ public class EnableIntegrationTests {
|
||||
@Autowired
|
||||
private PollableChannel messageChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel messageChannel2;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel fooChannel;
|
||||
|
||||
@@ -432,6 +435,12 @@ public class EnableIntegrationTests {
|
||||
assertThat(message.getHeaders().containsKey("foo")).isTrue();
|
||||
assertThat(message.getHeaders().get("foo")).isEqualTo("FOO");
|
||||
|
||||
message = this.messageChannel2.receive(10_000);
|
||||
assertThat(message).isNotNull();
|
||||
assertThat(message.getPayload()).isEqualTo("bar");
|
||||
assertThat(message.getHeaders().containsKey("foo")).isTrue();
|
||||
assertThat(message.getHeaders().get("foo")).isEqualTo("FOO");
|
||||
|
||||
MessagingTemplate messagingTemplate = new MessagingTemplate(this.controlBusChannel);
|
||||
assertThat(messagingTemplate.convertSendAndReceive("@pausable.isRunning()", Boolean.class)).isEqualTo(false);
|
||||
this.controlBusChannel.send(new GenericMessage<>("@pausable.start()"));
|
||||
@@ -1162,6 +1171,11 @@ public class EnableIntegrationTests {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PollableChannel messageChannel2() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public QueueChannel numberChannel() {
|
||||
QueueChannel channel = new QueueChannel();
|
||||
@@ -1354,6 +1368,7 @@ public class EnableIntegrationTests {
|
||||
|
||||
@InboundChannelAdapter(value = "messageChannel", poller = @Poller(fixedDelay = "${poller.interval}",
|
||||
maxMessagesPerPoll = "1"))
|
||||
@InboundChannelAdapter(value = "messageChannel2", poller = @Poller(fixedDelay = "100"))
|
||||
public Message<?> message() {
|
||||
return MessageBuilder.withPayload("bar").setHeader("foo", "FOO").build();
|
||||
}
|
||||
|
||||
@@ -301,7 +301,7 @@ public class ThingService {
|
||||
----
|
||||
====
|
||||
|
||||
You can also use the `@Headers` annotation to provide all of the message headers as a `Map`, as the following example shows:
|
||||
You can also use the `@Headers` annotation to provide all the message headers as a `Map`, as the following example shows:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
@@ -354,7 +354,7 @@ The `MessageHandler` instances (`MessageSource` instances) are also eligible to
|
||||
|
||||
Starting with version 4.0, all messaging annotations provide `SmartLifecycle` options (`autoStartup` and `phase`) to allow endpoint lifecycle control on application context initialization.
|
||||
They default to `true` and `0`, respectively.
|
||||
To change the state of an endpoint (such as ` start()` or `stop()`), you can obtain a reference to the endpoint bean by using the `BeanFactory` (or autowiring) and invoke the methods.
|
||||
To change the state of an endpoint (such as `start()` or `stop()`), you can obtain a reference to the endpoint bean by using the `BeanFactory` (or autowiring) and invoke the methods.
|
||||
Alternatively, you can send a command message to the `Control Bus` (see <<./control-bus.adoc#control-bus,Control Bus>>).
|
||||
For these purposes, you should use the `beanName` mentioned earlier in the preceding paragraph.
|
||||
|
||||
@@ -380,6 +380,18 @@ Thing1 dependsOnSPCA(@Qualifier("someInboundAdapter") @Lazy SourcePollingChannel
|
||||
====
|
||||
=====
|
||||
|
||||
Starting with version 6.0, all the messaging annotations are `@Repeatable` now, so several of the same type can be declared on the same service method with the meaning to create as many endpoints as those annotations are repeated:
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@Transformer(inputChannel = "inputChannel1", outputChannel = "outputChannel1")
|
||||
@Transformer(inputChannel = "inputChannel2", outputChannel = "outputChannel2")
|
||||
public String transform(String input) {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[configuration-using-poller-annotation]]
|
||||
==== Using the `@Poller` Annotation
|
||||
|
||||
|
||||
@@ -26,8 +26,10 @@ See <<./graphql.adoc#graphql,GraphQL Support>> for more information.
|
||||
[[x6.0-general]]
|
||||
=== General Changes
|
||||
|
||||
The messaging annotations don't require a poller attribute as an array of @Poller any more.
|
||||
See <<./configuration.adoc#configuration-using-poller-annotation,Using the @Poller Annotation>> for more information.
|
||||
The messaging annotations are now `@Repeatable` and the same type can be declared several times on the same service method.
|
||||
The messaging annotations don't require a `poller` attribute as an array of `@Poller` anymore.
|
||||
|
||||
See <<./configuration.adoc#annotations,Annotation Support>> for more information.
|
||||
|
||||
[[x6.0-http]]
|
||||
=== HTTP Changes
|
||||
|
||||
Reference in New Issue
Block a user