From 68c0df5286e9fd762faba628a6efc9252a8a7df2 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Mon, 14 Dec 2015 12:12:47 -0500 Subject: [PATCH] INT-3911: Restore removed `@Deprecated` JIRA: https://jira.spring.io/browse/INT-3911 Deffer the removal to `5.0` --- .../PassThroughMessageGroupProcessor.java | 36 +++++++++ .../integration/annotation/Header.java | 50 ++++++++++++ .../integration/annotation/Headers.java | 41 ++++++++++ .../integration/annotation/Payload.java | 51 ++++++++++++ ...thodAnnotationPublisherMetadataSource.java | 16 +++- .../config/IntegrationRegistrar.java | 10 ++- .../context/IntegrationObjectSupport.java | 4 +- .../IntegrationEvaluationContextAware.java | 46 +++++++++++ ...aluationContextAwareBeanPostProcessor.java | 80 +++++++++++++++++++ .../GatewayMethodInboundMessageMapper.java | 16 +++- .../gateway/GatewayProxyFactoryBean.java | 5 +- .../util/MessagingAnnotationUtils.java | 5 +- .../util/MessagingMethodInvokerHelper.java | 9 ++- 13 files changed, 352 insertions(+), 17 deletions(-) create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/aggregator/PassThroughMessageGroupProcessor.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/annotation/Header.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/annotation/Headers.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAware.java create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aggregator/PassThroughMessageGroupProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/PassThroughMessageGroupProcessor.java new file mode 100644 index 0000000000..2d778c1822 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/aggregator/PassThroughMessageGroupProcessor.java @@ -0,0 +1,36 @@ +/* + * Copyright 2002-2015 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 + * + * http://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.aggregator; + +import org.springframework.integration.store.MessageGroup; + +/** + * This implementation of MessageGroupProcessor will return all messages inside the group. + * This is useful if there is no requirement to process the messages, but they should just be + * blocked as a group until their ReleaseStrategy lets them pass through. + * + * @deprecated since 4.2; use {@link SimpleMessageGroupProcessor} + * + * @author Iwein Fuld + * @since 2.0.0 + */ +@Deprecated +public class PassThroughMessageGroupProcessor implements MessageGroupProcessor { + + @Override + public Object processMessageGroup(MessageGroup group) { + return group.getMessages(); + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Header.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Header.java new file mode 100644 index 0000000000..ce8bb48e20 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Header.java @@ -0,0 +1,50 @@ +/* + * Copyright 2002-2010 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 + * + * http://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; + +/** + * Annotation indicating that a method parameter's value should be + * retrieved from the message headers. The value of the annotation + * can either be a header name (e.g., 'foo') or SpEL expression + * (e.g., 'payload.getCustomerId()') which is quite useful when + * the name of the header has to be dynamically computed. It also + * provides an optional 'required' property which + * specifies whether the attribute value must be available within + * the header. The default value for 'required' is true. + * + * @author Mark Fisher + * + * @deprecated since 4.1 in favor of {@link org.springframework.messaging.handler.annotation.Header}. + * Will be removed in a future release. + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Deprecated +public @interface Header { + + String value() default ""; + + boolean required() default true; + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Headers.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Headers.java new file mode 100644 index 0000000000..8a67f7f13f --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Headers.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2010 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 + * + * http://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; + +/** + * Annotation indicating that a method parameter's value should be mapped to or + * from the message headers. The annotated parameter must be assignable to + * {@link java.util.Map}, and all of the Map's keys must be Strings. + * + * @author Mark Fisher + * + * @deprecated since 4.1 in favor of {@link org.springframework.messaging.handler.annotation.Headers}. + * Will be removed in a future release. + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Deprecated +public @interface Headers { + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java new file mode 100644 index 0000000000..79a947aec1 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Payload.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2014 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 + * + * http://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; + +/** + * This annotation allows you to specify a SpEL expression indicating that a method + * parameter's value should be mapped from the payload of a Message. The expression + * will be evaluated against the payload object as the root context. The annotated + * parameter type must match or be convertible from the evaluation result. + *

+ * Example: void foo(@Payload("city.name") String cityName) - will map the value of + * the 'name' property of the 'city' property of the payload object. + * + * @author Oleg Zhurakousky + * @since 2.0 + * + * @deprecated since 4.1 in favor of {@link org.springframework.messaging.handler.annotation.Payload}. + * Will be removed in a future release. + */ +@Target({ElementType.PARAMETER, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Deprecated +public @interface Payload { + + /** + * @return The expression for matching against nested properties of the payload. + */ + String value() default ""; + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationPublisherMetadataSource.java b/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationPublisherMetadataSource.java index e53b419258..0a0b197de0 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationPublisherMetadataSource.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/aop/MethodAnnotationPublisherMetadataSource.java @@ -72,9 +72,14 @@ public class MethodAnnotationPublisherMetadataSource implements PublisherMetadat return (StringUtils.hasText(channelName) ? channelName : null); } + @SuppressWarnings("deprecation") public String getPayloadExpression(Method method) { String payloadExpression = null; - Annotation methodPayloadAnnotation = AnnotationUtils.findAnnotation(method, Payload.class); + Annotation methodPayloadAnnotation = + AnnotationUtils.findAnnotation(method, org.springframework.integration.annotation.Payload.class); + if (methodPayloadAnnotation == null) { + methodPayloadAnnotation = AnnotationUtils.findAnnotation(method, Payload.class); + } if (methodPayloadAnnotation != null) { payloadExpression = getAnnotationValue(methodPayloadAnnotation, null, String.class); @@ -87,7 +92,8 @@ public class MethodAnnotationPublisherMetadataSource implements PublisherMetadat for (int i = 0; i < annotationArray.length; i++) { Annotation[] parameterAnnotations = annotationArray[i]; for (Annotation currentAnnotation : parameterAnnotations) { - if (Payload.class.equals(currentAnnotation.annotationType())) { + if (org.springframework.integration.annotation.Payload.class.equals(currentAnnotation.annotationType()) + || Payload.class.equals(currentAnnotation.annotationType())) { Assert.state(payloadExpression == null, "@Payload can be used at most once on a @Publisher method, " + "either at method-level or on a single parameter"); @@ -101,11 +107,12 @@ public class MethodAnnotationPublisherMetadataSource implements PublisherMetadat || payloadExpression.contains("#" + PublisherMetadataSource.RETURN_VALUE_VARIABLE_NAME)) { Assert.isTrue(!void.class.equals(method.getReturnType()), "When defining @Publisher on a void-returning method, an explicit payload " + - "expression that does not rely upon a #return value is required."); + "expression that does not rely upon a #return value is required."); } return payloadExpression; } + @SuppressWarnings("deprecation") public Map getHeaderExpressions(Method method) { Map headerExpressions = new HashMap(); String[] parameterNames = this.parameterNameDiscoverer.getParameterNames(method); @@ -113,7 +120,8 @@ public class MethodAnnotationPublisherMetadataSource implements PublisherMetadat for (int i = 0; i < annotationArray.length; i++) { Annotation[] parameterAnnotations = annotationArray[i]; for (Annotation currentAnnotation : parameterAnnotations) { - if (Header.class.equals(currentAnnotation.annotationType())) { + if (org.springframework.integration.annotation.Header.class.equals(currentAnnotation.annotationType()) + || Header.class.equals(currentAnnotation.annotationType())) { String name = getAnnotationValue(currentAnnotation, null, String.class); if (!StringUtils.hasText(name)) { name = parameterNames[i]; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java index e67b925845..afe7e7793d 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationRegistrar.java @@ -36,6 +36,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedSet; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; @@ -185,8 +186,13 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean new BeanDefinitionHolder(integrationEvaluationContextBuilder.getBeanDefinition(), IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME); - BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder, - registry); + BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder, registry); + + //TODO Remove this registration in 5.0 + RootBeanDefinition integrationEvalContextBPP = + new RootBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE + + ".expression.IntegrationEvaluationContextAwareBeanPostProcessor"); + BeanDefinitionReaderUtils.registerWithGeneratedName(integrationEvalContextBPP, registry); } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java index d65af4801f..6e4a94f1f1 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationObjectSupport.java @@ -65,13 +65,13 @@ import org.springframework.util.StringUtils; public abstract class IntegrationObjectSupport implements BeanNameAware, NamedComponent, ApplicationContextAware, BeanFactoryAware, InitializingBean { + protected static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); + /** * Logger that is available to subclasses */ protected final Log logger = LogFactory.getLog(getClass()); - protected final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser(); - private final ConversionService defaultConversionService = new DefaultConversionService(); private volatile DestinationResolver channelResolver; diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAware.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAware.java new file mode 100644 index 0000000000..815c233109 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAware.java @@ -0,0 +1,46 @@ +/* + * Copyright 2013 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 + * + * http://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.expression; + +import org.springframework.expression.EvaluationContext; +import org.springframework.integration.context.IntegrationContextUtils; + +/** + * Interface to be implemented by beans that wish to be aware of their + * owning integration {@link EvaluationContext}, which is the result of + * {@link org.springframework.integration.config.IntegrationEvaluationContextFactoryBean} + *

+ * The {@link #setIntegrationEvaluationContext} is invoked from + * the {@code IntegrationEvaluationContextAwareBeanPostProcessor#afterSingletonsInstantiated()}, + * not during standard {@code postProcessBefore(After)Initialization} to avoid any + * {@code BeanFactory} early access during integration {@link EvaluationContext} retrieval. + * Therefore, if it is necessary to use {@link EvaluationContext} in the {@code afterPropertiesSet()}, + * the {@code IntegrationContextUtils.getEvaluationContext(this.beanFactory)} should be used instead + * of this interface implementation. + * + * @author Artem Bilan + * @since 3.0 + * @deprecated since 4.2 in favor of {@link IntegrationContextUtils#getEvaluationContext} + * direct usage from the {@code afterPropertiesSet} implementation. + * Will be removed in the next release. + */ +@Deprecated +public interface IntegrationEvaluationContextAware { + + void setIntegrationEvaluationContext(EvaluationContext evaluationContext); + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java new file mode 100644 index 0000000000..2e118e1c29 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/IntegrationEvaluationContextAwareBeanPostProcessor.java @@ -0,0 +1,80 @@ +/* + * Copyright 2013-2015 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 + * + * http://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.expression; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.SmartInitializingSingleton; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.integration.context.IntegrationContextUtils; + +/** + * @author Artem Bilan + * @author Gary Russell + * @since 3.0 + * @deprecated since 4.2 in favor of {@link IntegrationContextUtils#getEvaluationContext} + * direct usage from the {@code afterPropertiesSet} implementation. + * Will be removed in the next release. + */ +@Deprecated +@SuppressWarnings("deprecation") +public class IntegrationEvaluationContextAwareBeanPostProcessor + implements BeanPostProcessor, Ordered, BeanFactoryAware, SmartInitializingSingleton { + + private final List evaluationContextAwares = + new ArrayList(); + + private volatile BeanFactory beanFactory; + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof IntegrationEvaluationContextAware) { + this.evaluationContextAwares.add((IntegrationEvaluationContextAware) bean); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + @Override + public void afterSingletonsInstantiated() { + StandardEvaluationContext evaluationContext = IntegrationContextUtils.getEvaluationContext(this.beanFactory); + for (IntegrationEvaluationContextAware evaluationContextAware : this.evaluationContextAwares) { + evaluationContextAware.setIntegrationEvaluationContext(evaluationContext); + } + } + + @Override + public int getOrder() { + return LOWEST_PRECEDENCE; + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java index 5eeb708c03..a2bfc00cdf 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/gateway/GatewayMethodInboundMessageMapper.java @@ -244,9 +244,13 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper toMessage(MethodArgsHolder holder) throws Exception { Object messageOrPayload = null; boolean foundPayloadAnnotation = false; @@ -275,7 +280,8 @@ class GatewayMethodInboundMessageMapper implements InboundMessageMapper type = annotation.annotationType(); - if (type.equals(Payload.class) + if (type.equals(org.springframework.integration.annotation.Payload.class) + || type.equals(Payload.class) + || type.equals(org.springframework.integration.annotation.Header.class) || type.equals(Header.class) + || type.equals(org.springframework.integration.annotation.Headers.class) || type.equals(Headers.class) || (payloads && type.equals(Payloads.class))) { if (match != null) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java index e84122f639..9ca108ecb3 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/util/MessagingMethodInvokerHelper.java @@ -714,7 +714,8 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator MessagingAnnotationUtils.findMessagePartAnnotation(parameterAnnotations[i], true); if (mappingAnnotation != null) { Class annotationType = mappingAnnotation.annotationType(); - if (annotationType.equals(Payload.class)) { + if (annotationType.equals(org.springframework.integration.annotation.Payload.class) + || annotationType.equals(Payload.class)) { sb.append("payload"); String qualifierExpression = (String) AnnotationUtils.getValue(mappingAnnotation); if (StringUtils.hasText(qualifierExpression)) { @@ -735,12 +736,14 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator this.setExclusiveTargetParameterType(parameterTypeDescriptor, methodParameter); } } - else if (annotationType.equals(Headers.class)) { + else if (annotationType.equals(org.springframework.integration.annotation.Headers.class) + || annotationType.equals(Headers.class)) { Assert.isTrue(Map.class.isAssignableFrom(parameterType), "The @Headers annotation can only be applied to a Map-typed parameter."); sb.append("headers"); } - else if (annotationType.equals(Header.class)) { + else if (annotationType.equals(org.springframework.integration.annotation.Header.class) + || annotationType.equals(Header.class)) { sb.append(this.determineHeaderExpression(mappingAnnotation, methodParameter)); } }