Post merge polishing

JIRA: https://jira.spring.io/browse/INT-4363

* Register `HandlerMethodArgumentResolver`s in the
`IntegrationRegistrar` as `BeanDefinition`s to let them be configured by
the `BeanFactory` callback.
The direct instance doesn't call callbacks
* Use `JacksonPresent` in the `IntegrationRegistrar` instead of local
property
* Some code style polishing for the `IntegrationRegistrar`
* Add `JsonPathTests.testJsonPathOnPayloadAnnotation()` to ensure
that `PayloadExpressionArgumentResolver` is properly configured by the
`BeanFactory` and `#jsonPath()` SpEL-function is properly evaluated on
the `@Payload` for method `@ServiceActivator` method argument
This commit is contained in:
Artem Bilan
2017-11-15 14:00:50 -05:00
parent 986d5fc0cd
commit 9414ceef86
6 changed files with 152 additions and 106 deletions

View File

@@ -26,6 +26,7 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
* A holder for the configured argument resolvers.
*
* @author Gary Russell
*
* @since 5.0
*
*/

View File

@@ -37,6 +37,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
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;
@@ -54,9 +55,10 @@ import org.springframework.integration.handler.support.PayloadsArgumentResolver;
import org.springframework.integration.support.DefaultMessageBuilderFactory;
import org.springframework.integration.support.converter.ConfigurableCompositeMessageConverter;
import org.springframework.integration.support.converter.DefaultDatatypeChannelMessageConverter;
import org.springframework.integration.support.json.JacksonPresent;
import org.springframework.integration.support.utils.IntegrationUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.converter.CompositeMessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.util.ClassUtils;
/**
@@ -64,6 +66,7 @@ import org.springframework.util.ClassUtils;
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 4.0
*/
public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, BeanClassLoaderAware {
@@ -73,17 +76,13 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
private final static IntegrationConverterInitializer INTEGRATION_CONVERTER_INITIALIZER =
new IntegrationConverterInitializer();
private static final Set<Integer> registriesProcessed = new HashSet<Integer>();
private static final Set<Integer> registriesProcessed = new HashSet<>();
private ClassLoader classLoader;
private volatile boolean jackson2Present;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
this.jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
}
/**
@@ -93,7 +92,9 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
* to register the messaging annotation post processors (for {@code <int:annotation-config/>}).
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
public void registerBeanDefinitions(@Nullable AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
registerImplicitChannelCreator(registry);
registerIntegrationConfigurationBeanFactoryPostProcessor(registry);
registerIntegrationEvaluationContext(registry);
@@ -280,13 +281,15 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
.isBeanNameInUse(IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME);
}
if (!alreadyRegistered && !registriesProcessed.contains(registryId) && this.jackson2Present) {
registry.registerBeanDefinition(IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME,
if (!alreadyRegistered && !registriesProcessed.contains(registryId) && JacksonPresent.isJackson2Present()) {
registry.registerBeanDefinition(
IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME,
BeanDefinitionBuilder.genericBeanDefinition(IntegrationConfigUtils.BASE_PACKAGE +
".json.ToStringFriendlyJsonNodeToStringConverter")
.getBeanDefinition());
INTEGRATION_CONVERTER_INITIALIZER.registerConverter(registry,
new RuntimeBeanReference(IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME));
new RuntimeBeanReference(
IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME));
}
registriesProcessed.add(registryId);
@@ -303,7 +306,8 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
.containsBean(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
}
else {
alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
alreadyRegistered =
registry.isBeanNameInUse(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME);
}
if (!alreadyRegistered) {
BeanDefinitionBuilder postProcessorBuilder =
@@ -422,8 +426,7 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
* @param registry the registry.
*/
private void registerArgumentResolverMessageConverter(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(
IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)) {
BeanDefinitionBuilder converterBuilder = BeanDefinitionBuilder
.genericBeanDefinition(ConfigurableCompositeMessageConverter.class);
registry.registerBeanDefinition(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME,
@@ -439,7 +442,7 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
private void registerArgumentResolvers(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME)) {
registry.registerBeanDefinition(IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME,
internalArgumentResolversBuilder(registry, false).getBeanDefinition());
internalArgumentResolversBuilder(false));
}
}
@@ -449,22 +452,25 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean
* @param registry the registry.
*/
private void registerListCapableArgumentResolvers(BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(
IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME)) {
if (!registry.containsBeanDefinition(IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME)) {
registry.registerBeanDefinition(IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME,
internalArgumentResolversBuilder(registry, true).getBeanDefinition());
internalArgumentResolversBuilder(true));
}
}
private BeanDefinitionBuilder internalArgumentResolversBuilder(BeanDefinitionRegistry registry,
boolean listCapable) {
ManagedList<HandlerMethodArgumentResolver> resolvers = new ManagedList<>();
resolvers.add(new PayloadExpressionArgumentResolver());
resolvers.add(new PayloadsArgumentResolver());
resolvers.add(new CollectionArgumentResolver(listCapable));
resolvers.add(new MapArgumentResolver());
private BeanDefinition internalArgumentResolversBuilder(boolean listCapable) {
ManagedList<BeanDefinition> resolvers = new ManagedList<>();
resolvers.add(new RootBeanDefinition(PayloadExpressionArgumentResolver.class));
resolvers.add(new RootBeanDefinition(PayloadsArgumentResolver.class));
resolvers.add(new RootBeanDefinition(MapArgumentResolver.class));
resolvers.add(
BeanDefinitionBuilder.genericBeanDefinition(CollectionArgumentResolver.class)
.addConstructorArgValue(listCapable)
.getBeanDefinition());
return BeanDefinitionBuilder.genericBeanDefinition(HandlerMethodArgumentResolversHolder.class)
.addConstructorArgValue(resolvers);
.addConstructorArgValue(resolvers)
.getBeanDefinition();
}
private void registerMessageBuilderFactory(BeanDefinitionRegistry registry) {

View File

@@ -58,11 +58,11 @@ public abstract class IntegrationContextUtils {
public static final String DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME = "DefaultConfiguringBeanFactoryPostProcessor";
public static final String MESSAGING_ANNOTATION_POSTPROCESSOR_NAME = IntegrationConfigUtils.BASE_PACKAGE
+ ".internalMessagingAnnotationPostProcessor";
public static final String MESSAGING_ANNOTATION_POSTPROCESSOR_NAME =
IntegrationConfigUtils.BASE_PACKAGE + ".internalMessagingAnnotationPostProcessor";
public static final String PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME = IntegrationConfigUtils.BASE_PACKAGE
+ ".internalPublisherAnnotationBeanPostProcessor";
public static final String PUBLISHER_ANNOTATION_POSTPROCESSOR_NAME =
IntegrationConfigUtils.BASE_PACKAGE + ".internalPublisherAnnotationBeanPostProcessor";
public static final String INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME =
"IntegrationConfigurationBeanFactoryPostProcessor";
@@ -75,8 +75,7 @@ public abstract class IntegrationContextUtils {
public static final String INTEGRATION_FIXED_SUBSCRIBER_CHANNEL_BPP_BEAN_NAME =
"fixedSubscriberChannelBeanFactoryPostProcessor";
public static final String GLOBAL_CHANNEL_INTERCEPTOR_PROCESSOR_BEAN_NAME =
"globalChannelInterceptorProcessor";
public static final String GLOBAL_CHANNEL_INTERCEPTOR_PROCESSOR_BEAN_NAME = "globalChannelInterceptorProcessor";
public static final String TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME =
"toStringFriendlyJsonNodeToStringConverter";

View File

@@ -42,6 +42,7 @@ import org.springframework.util.Assert;
* to convert the value to the target type.
*
* @author Artem Bilan
* @author Gary Russell
*
* @since 5.0
*/
@@ -71,6 +72,7 @@ public class CollectionArgumentResolver extends AbstractExpressionEvaluator
Assert.state(value instanceof Collection,
"This Argument Resolver only supports messages with a payload of Collection<Message<?>>, "
+ "payload is: " + value.getClass());
Collection<Message<?>> messages = (Collection<Message<?>>) value;
parameter.increaseNestingLevel();

View File

@@ -130,14 +130,14 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
private static final ExpressionParser EXPRESSION_PARSER_DEFAULT = EXPRESSION_PARSER;
private static final ExpressionParser EXPRESSION_PARSER_OFF = new SpelExpressionParser(
new SpelParserConfiguration(SpelCompilerMode.OFF, null));
private static final ExpressionParser EXPRESSION_PARSER_OFF =
new SpelExpressionParser(new SpelParserConfiguration(SpelCompilerMode.OFF, null));
private static final ExpressionParser EXPRESSION_PARSER_IMMEDIATE = new SpelExpressionParser(
new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null));
private static final ExpressionParser EXPRESSION_PARSER_IMMEDIATE =
new SpelExpressionParser(new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null));
private static final ExpressionParser EXPRESSION_PARSER_MIXED = new SpelExpressionParser(
new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
private static final ExpressionParser EXPRESSION_PARSER_MIXED =
new SpelExpressionParser(new SpelParserConfiguration(SpelCompilerMode.MIXED, null));
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER =
new LocalVariableTableParameterNameDiscoverer();
@@ -149,8 +149,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
@SuppressWarnings("unused")
private static final Collection<Message<?>> dummyMessages = Collections.emptyList();
private static final TypeDescriptor messageListTypeDescriptor = new TypeDescriptor(
ReflectionUtils.findField(MessagingMethodInvokerHelper.class, "dummyMessages"));
private static final TypeDescriptor messageListTypeDescriptor =
new TypeDescriptor(ReflectionUtils.findField(MessagingMethodInvokerHelper.class, "dummyMessages"));
private static final TypeDescriptor messageArrayTypeDescriptor = TypeDescriptor.valueOf(Message[].class);
@@ -201,6 +201,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
public MessagingMethodInvokerHelper(Object targetObject, Method method, Class<?> expectedType,
boolean canProcessMessageList) {
this(targetObject, null, method, expectedType, canProcessMessageList);
}
@@ -210,6 +211,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
public MessagingMethodInvokerHelper(Object targetObject, String methodName, Class<?> expectedType,
boolean canProcessMessageList) {
this(targetObject, null, methodName, expectedType, canProcessMessageList);
}
@@ -219,14 +221,60 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
public MessagingMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
boolean canProcessMessageList) {
this(targetObject, annotationType, null, canProcessMessageList);
}
public MessagingMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
Class<?> expectedType, boolean canProcessMessageList) {
this(targetObject, annotationType, (String) null, expectedType, canProcessMessageList);
}
private MessagingMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
Method method, Class<?> expectedType, boolean canProcessMessageList) {
this.annotationType = annotationType;
this.canProcessMessageList = canProcessMessageList;
Assert.notNull(method, "method must not be null");
this.method = method;
this.requiresReply = expectedType != null;
if (expectedType != null) {
Assert.isTrue(method.getReturnType() != Void.class && method.getReturnType() != Void.TYPE,
"method must have a return type");
this.expectedType = TypeDescriptor.valueOf(expectedType);
}
else {
this.expectedType = null;
}
Assert.notNull(targetObject, "targetObject must not be null");
this.targetObject = targetObject;
try {
InvocableHandlerMethod invocableHandlerMethod =
this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method);
this.handlerMethod = new HandlerMethod(invocableHandlerMethod, canProcessMessageList);
this.defaultHandlerMethod = null;
checkSpelInvokerRequired(getTargetClass(targetObject), method, this.handlerMethod);
}
catch (IneligibleMethodException e) {
throw new IllegalArgumentException(e);
}
this.handlerMethods = null;
this.handlerMessageMethods = null;
this.handlerMethodsList = null;
setDisplayString(targetObject, method);
JsonObjectMapper<?, ?> mapper;
try {
mapper = JsonObjectMapperProvider.newInstance();
}
catch (IllegalStateException e) {
mapper = null;
}
this.jsonObjectMapper = mapper;
}
/**
* A {@code boolean} flag to use SpEL Expression evaluation or {@link InvocableHandlerMethod}
* for target method invocation.
@@ -247,8 +295,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
if (beanExpressionResolver != null) {
this.resolver = beanExpressionResolver;
}
this.expressionContext =
new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
this.expressionContext = new BeanExpressionContext((ConfigurableListableBeanFactory) beanFactory, null);
}
}
@@ -278,7 +325,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
Class<?> type = this.handlerMethod.getTargetParameterType();
if ((message.getPayload() instanceof String && !type.equals(String.class)
|| message.getPayload() instanceof byte[] && !type.equals(byte[].class))
&& contentTypeIsJson(message)) {
&& contentTypeIsJson(message)) {
try {
return getMessageBuilderFactory()
.withPayload(this.jsonObjectMapper.fromJson(message.getPayload(), type))
@@ -297,7 +345,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
private boolean contentTypeIsJson(Message<?> message) {
Object contentType = message.getHeaders().get(MessageHeaders.CONTENT_TYPE);
return contentType != null ? contentType.toString().contains("json") : false;
return contentType != null && contentType.toString().contains("json");
}
public T process(Collection<Message<?>> messages, Map<String, Object> headers) throws Exception {
@@ -333,48 +381,6 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
* Private constructors for internal use
*/
private MessagingMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
Method method, Class<?> expectedType, boolean canProcessMessageList) {
this.annotationType = annotationType;
this.canProcessMessageList = canProcessMessageList;
Assert.notNull(method, "method must not be null");
this.method = method;
this.requiresReply = expectedType != null;
if (expectedType != null) {
Assert.isTrue(method.getReturnType() != Void.class && method.getReturnType() != Void.TYPE,
"method must have a return type");
this.expectedType = TypeDescriptor.valueOf(expectedType);
}
else {
this.expectedType = null;
}
Assert.notNull(targetObject, "targetObject must not be null");
this.targetObject = targetObject;
try {
InvocableHandlerMethod invocableHandlerMethod =
this.messageHandlerMethodFactory.createInvocableHandlerMethod(targetObject, method);
this.handlerMethod = new HandlerMethod(invocableHandlerMethod, canProcessMessageList);
this.defaultHandlerMethod = null;
checkSpelInvokerRequired(getTargetClass(targetObject), method, this.handlerMethod);
}
catch (IneligibleMethodException e) {
throw new IllegalArgumentException(e);
}
this.handlerMethods = null;
this.handlerMessageMethods = null;
this.handlerMethodsList = null;
this.setDisplayString(targetObject, method);
JsonObjectMapper<?, ?> mapper;
try {
mapper = JsonObjectMapperProvider.newInstance();
}
catch (IllegalStateException e) {
mapper = null;
}
this.jsonObjectMapper = mapper;
}
private MessagingMethodInvokerHelper(Object targetObject, Class<? extends Annotation> annotationType,
String methodName, Class<?> expectedType, boolean canProcessMessageList) {
this.annotationType = annotationType;
@@ -517,8 +523,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
String compilerMode = resolveExpression(candidate.useSpelInvoker.compilerMode(),
"UseSpelInvoker.compilerMode:").toUpperCase();
parser = !StringUtils.hasText(compilerMode)
? EXPRESSION_PARSER_DEFAULT
: SPEL_COMPILERS.get(SpelCompilerMode.valueOf(compilerMode));
? EXPRESSION_PARSER_DEFAULT
: SPEL_COMPILERS.get(SpelCompilerMode.valueOf(compilerMode));
}
candidate.expression = parser.parseExpression(candidate.expressionString);
candidate.initialized = true;
@@ -526,23 +532,25 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
private synchronized void initialize() throws Exception {
if (!this.initialized) {
if (getBeanFactory() != null
&& getBeanFactory().containsBean(
IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)) {
BeanFactory beanFactory = getBeanFactory();
if (beanFactory != null &&
beanFactory.containsBean(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME)) {
try {
this.messageHandlerMethodFactory.setMessageConverter(getBeanFactory().getBean(
IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME,
MessageConverter.class));
if (this.canProcessMessageList) {
this.messageHandlerMethodFactory.setCustomArgumentResolvers(getBeanFactory().getBean(
IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME,
HandlerMethodArgumentResolversHolder.class).getResolvers());
}
else {
this.messageHandlerMethodFactory.setCustomArgumentResolvers(getBeanFactory().getBean(
IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME,
HandlerMethodArgumentResolversHolder.class).getResolvers());
}
MessageConverter messageConverter =
beanFactory.getBean(IntegrationContextUtils.ARGUMENT_RESOLVER_MESSAGE_CONVERTER_BEAN_NAME,
MessageConverter.class);
this.messageHandlerMethodFactory.setMessageConverter(messageConverter);
HandlerMethodArgumentResolversHolder handlerMethodArgumentResolversHolder =
beanFactory.getBean(this.canProcessMessageList
? IntegrationContextUtils.LIST_ARGUMENT_RESOLVERS_BEAN_NAME
: IntegrationContextUtils.ARGUMENT_RESOLVERS_BEAN_NAME,
HandlerMethodArgumentResolversHolder.class);
this.messageHandlerMethodFactory.setCustomArgumentResolvers(
handlerMethodArgumentResolversHolder.getResolvers());
}
catch (NoSuchBeanDefinitionException e) {
configureLocalMessageHandlerFactory();
@@ -551,6 +559,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
else {
configureLocalMessageHandlerFactory();
}
this.messageHandlerMethodFactory.afterPropertiesSet();
prepareEvaluationContext();
this.initialized = true;
@@ -562,8 +571,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
* that don't run in an application context.
*/
private void configureLocalMessageHandlerFactory() {
PayloadExpressionArgumentResolver payloadExpressionArgumentResolver =
new PayloadExpressionArgumentResolver();
PayloadExpressionArgumentResolver payloadExpressionArgumentResolver = new PayloadExpressionArgumentResolver();
payloadExpressionArgumentResolver.setBeanFactory(getBeanFactory());
PayloadsArgumentResolver payloadsArgumentResolver = new PayloadsArgumentResolver();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 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.
@@ -39,10 +39,15 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.integration.MessageRejectedException;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.config.EnableIntegration;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.PollableChannel;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -56,6 +61,7 @@ import com.jayway.jsonpath.Predicate;
/**
* @author Artem Bilan
* @author Gary Russell
*
* @since 3.0
*/
@ContextConfiguration(classes = JsonPathTests.JsonPathTestsContextConfiguration.class,
@@ -207,9 +213,28 @@ public class JsonPathTests {
assertNull(this.routerOutput1.receive(10));
}
@Autowired
private MessageChannel jsonPathMessageChannel;
@Test
public void testJsonPathOnPayloadAnnotation() {
QueueChannel replyChannel = new QueueChannel();
Message<String> message = MessageBuilder.withPayload(JSON)
.setHeader(MessageHeaders.REPLY_CHANNEL, replyChannel)
.build();
this.jsonPathMessageChannel.send(message);
Message<?> receive = replyChannel.receive(10_000);
assertNotNull(receive);
assertEquals("Nigel Rees", receive.getPayload());
}
@Configuration
@ImportResource("classpath:org/springframework/integration/json/JsonPathTests-context.xml")
@EnableIntegration
public static class JsonPathTestsContextConfiguration {
@Bean
@@ -217,6 +242,11 @@ public class JsonPathTests {
return Filter.filter(Criteria.where("isbn").exists(true).and("category").ne("fiction"));
}
@ServiceActivator(inputChannel = "jsonPathMessageChannel")
public String handle(@Payload("#jsonPath(#root, '$.store.book[0].author')") String payload) {
return payload;
}
}
}