From 85866a2ea89ab652b7df71403177f1cf4873fb97 Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 4 Jul 2014 18:33:50 +0300 Subject: [PATCH] INT-3427: Add `JsonNodeToStringConverter` JIRA: https://jira.spring.io/browse/INT-3427 INT-3427: Workaround for String -> File converter INT-3427: PR comments --- .../config/IntegrationRegistrar.java | 129 ++++++++++++------ .../AbstractIntegrationNamespaceHandler.java | 4 +- .../context/IntegrationContextUtils.java | 3 + ...ringFriendlyJsonNodeToStringConverter.java | 38 ++++++ .../expression/ParentContext-context.xml | 13 ++ .../expression/ParentContextTests.java | 57 +++++++- .../integration/json/TestPerson.java | 6 +- .../AbstractRemoteFileOutboundGateway.java | 5 +- 8 files changed, 201 insertions(+), 54 deletions(-) create mode 100644 spring-integration-core/src/main/java/org/springframework/integration/json/ToStringFriendlyJsonNodeToStringConverter.java 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 7fb766eaf0..e87716fe5c 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 @@ -31,6 +31,7 @@ import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.PropertiesFactoryBean; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -63,13 +64,20 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean private static final Log logger = LogFactory.getLog(IntegrationRegistrar.class); + private final static IntegrationConverterInitializer INTEGRATION_CONVERTER_INITIALIZER = + new IntegrationConverterInitializer(); + private static final Set 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); } /** @@ -99,13 +107,14 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean * This method will auto-register a ChannelInitializer which could also be overridden by the user * by simply registering a ChannelInitializer {@code } with its {@code autoCreate} property * set to false to suppress channel creation. - * It will also register a ChannelInitializer$AutoCreateCandidatesCollector which simply collects candidate channel names. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * It will also register a ChannelInitializer$AutoCreateCandidatesCollector + * which simply collects candidate channel names. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerImplicitChannelCreator(BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(IntegrationContextUtils.CHANNEL_INITIALIZER_BEAN_NAME)) { - String channelsAutoCreateExpression = IntegrationProperties.getExpressionFor(IntegrationProperties.CHANNELS_AUTOCREATE); + String channelsAutoCreateExpression = + IntegrationProperties.getExpressionFor(IntegrationProperties.CHANNELS_AUTOCREATE); BeanDefinitionBuilder channelDef = BeanDefinitionBuilder.genericBeanDefinition(ChannelInitializer.class) .addPropertyValue("autoCreate", channelsAutoCreateExpression); BeanDefinitionHolder channelCreatorHolder = new BeanDefinitionHolder(channelDef.getBeanDefinition(), @@ -117,16 +126,16 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean BeanDefinitionBuilder channelRegistryBuilder = BeanDefinitionBuilder .genericBeanDefinition(ChannelInitializer.AutoCreateCandidatesCollector.class); channelRegistryBuilder.addConstructorArgValue(new ManagedSet()); - BeanDefinitionHolder channelRegistryHolder = new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(), - IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME); + BeanDefinitionHolder channelRegistryHolder = + new BeanDefinitionHolder(channelRegistryBuilder.getBeanDefinition(), + IntegrationContextUtils.AUTO_CREATE_CHANNEL_CANDIDATES_BEAN_NAME); BeanDefinitionReaderUtils.registerBeanDefinition(channelRegistryHolder, registry); } } /** * Register {@code integrationGlobalProperties} bean if necessary. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerIntegrationProperties(BeanDefinitionRegistry registry) { boolean alreadyRegistered = false; @@ -135,13 +144,16 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean .containsBean(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME); } else { - alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME); + alreadyRegistered = + registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_GLOBAL_PROPERTIES_BEAN_NAME); } if (!alreadyRegistered) { ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(this.classLoader); try { - Resource[] defaultResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.default.properties"); - Resource[] userResources = resourceResolver.getResources("classpath*:META-INF/spring.integration.properties"); + Resource[] defaultResources = + resourceResolver.getResources("classpath*:META-INF/spring.integration.default.properties"); + Resource[] userResources = + resourceResolver.getResources("classpath*:META-INF/spring.integration.properties"); List resources = new LinkedList(Arrays.asList(defaultResources)); resources.addAll(Arrays.asList(userResources)); @@ -162,8 +174,7 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean /** * Register {@link IntegrationEvaluationContextFactoryBean} bean * and {@link IntegrationEvaluationContextAwareBeanPostProcessor}, if necessary. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerIntegrationEvaluationContext(BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_EVALUATION_CONTEXT_BEAN_NAME)) { @@ -178,15 +189,15 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean BeanDefinitionReaderUtils.registerBeanDefinition(integrationEvaluationContextHolder, registry); - RootBeanDefinition integrationEvalContextBPP = new RootBeanDefinition(IntegrationEvaluationContextAwareBeanPostProcessor.class); + RootBeanDefinition integrationEvalContextBPP = + new RootBeanDefinition(IntegrationEvaluationContextAwareBeanPostProcessor.class); BeanDefinitionReaderUtils.registerWithGeneratedName(integrationEvalContextBPP, registry); } } /** * Register {@code jsonPath} and {@code xpath} SpEL-function beans, if necessary. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerBuiltInBeans(BeanDefinitionRegistry registry) { int registryId = System.identityHashCode(registry); @@ -205,7 +216,8 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean jsonPathClass = ClassUtils.forName("com.jayway.jsonpath.JsonPath", this.classLoader); } catch (ClassNotFoundException e) { - logger.debug("SpEL function '#jsonPath' isn't registered: there is no jayway json-path.jar on the classpath."); + logger.debug("SpEL function '#jsonPath' isn't registered: " + + "there is no jayway json-path.jar on the classpath."); } if (jsonPathClass != null) { @@ -225,10 +237,12 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean if (!alreadyRegistered && !registriesProcessed.contains(registryId)) { Class xpathClass = null; try { - xpathClass = ClassUtils.forName(IntegrationConfigUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils", this.classLoader); + xpathClass = ClassUtils.forName(IntegrationConfigUtils.BASE_PACKAGE + ".xml.xpath.XPathUtils", + this.classLoader); } catch (ClassNotFoundException e) { - logger.debug("SpEL function '#xpath' isn't registered: there is no spring-integration-xml.jar on the classpath."); + logger.debug("SpEL function '#xpath' isn't registered: " + + "there is no spring-integration-xml.jar on the classpath."); } if (xpathClass != null) { @@ -237,49 +251,73 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean } } + alreadyRegistered = false; + if (registry instanceof ListableBeanFactory) { + alreadyRegistered = ((ListableBeanFactory) registry) + .containsBean(IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME); + } + else { + alreadyRegistered = registry + .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, + 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)); + } + registriesProcessed.add(registryId); } /** * Register {@code DefaultConfiguringBeanFactoryPostProcessor}, if necessary. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerDefaultConfiguringBeanFactoryPostProcessor(BeanDefinitionRegistry registry) { boolean alreadyRegistered = false; if (registry instanceof ListableBeanFactory) { - alreadyRegistered = ((ListableBeanFactory) registry).containsBean(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME); + alreadyRegistered = ((ListableBeanFactory) registry) + .containsBean(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME); } else { alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME); } if (!alreadyRegistered) { - BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultConfiguringBeanFactoryPostProcessor.class); + BeanDefinitionBuilder postProcessorBuilder = + BeanDefinitionBuilder.genericBeanDefinition(DefaultConfiguringBeanFactoryPostProcessor.class); BeanDefinitionHolder postProcessorHolder = new BeanDefinitionHolder( - postProcessorBuilder.getBeanDefinition(), IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME); + postProcessorBuilder.getBeanDefinition(), + IntegrationContextUtils.DEFAULT_CONFIGURING_POSTPROCESSOR_BEAN_NAME); BeanDefinitionReaderUtils.registerBeanDefinition(postProcessorHolder, registry); } } /** * Register a {@link DefaultHeaderChannelRegistry} in the given {@link BeanDefinitionRegistry}, if necessary. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerHeaderChannelRegistry(BeanDefinitionRegistry registry) { boolean alreadyRegistered = false; if (registry instanceof ListableBeanFactory) { - alreadyRegistered = ((ListableBeanFactory) registry).containsBean(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME); + alreadyRegistered = ((ListableBeanFactory) registry) + .containsBean(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME); } else { - alreadyRegistered = registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME); + alreadyRegistered = + registry.isBeanNameInUse(IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME); } if (!alreadyRegistered) { if (logger.isInfoEnabled()) { logger.info("No bean named '" + IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME + - "' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created."); + "' has been explicitly defined. " + + "Therefore, a default DefaultHeaderChannelRegistry will be created."); } - BeanDefinitionBuilder schedulerBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultHeaderChannelRegistry.class); + BeanDefinitionBuilder schedulerBuilder = + BeanDefinitionBuilder.genericBeanDefinition(DefaultHeaderChannelRegistry.class); BeanDefinitionHolder replyChannelRegistryComponent = new BeanDefinitionHolder( schedulerBuilder.getBeanDefinition(), IntegrationContextUtils.INTEGRATION_HEADER_CHANNEL_REGISTRY_BEAN_NAME); @@ -289,51 +327,54 @@ public class IntegrationRegistrar implements ImportBeanDefinitionRegistrar, Bean /** * Register a {@link GlobalChannelInterceptorProcessor} in the given {@link BeanDefinitionRegistry}, if necessary. - * - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerGlobalChannelInterceptorProcessor(BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(IntegrationContextUtils.GLOBAL_CHANNEL_INTERCEPTOR_PROCESSOR_BEAN_NAME)) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(GlobalChannelInterceptorProcessor.class) - .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + BeanDefinitionBuilder builder = + BeanDefinitionBuilder.genericBeanDefinition(GlobalChannelInterceptorProcessor.class) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(IntegrationContextUtils.GLOBAL_CHANNEL_INTERCEPTOR_PROCESSOR_BEAN_NAME, builder.getBeanDefinition()); + registry.registerBeanDefinition(IntegrationContextUtils.GLOBAL_CHANNEL_INTERCEPTOR_PROCESSOR_BEAN_NAME, + builder.getBeanDefinition()); } } /** * Register {@link MessagingAnnotationPostProcessor} and {@link PublisherAnnotationBeanPostProcessor}, if necessary. * Inject {@code defaultPublishedChannel} from provided {@link AnnotationMetadata}, if any. - * - * @param meta The {@link AnnotationMetadata} to get additional properties for {@link org.springframework.beans.factory.config.BeanDefinition}s. - * @param registry The {@link BeanDefinitionRegistry} to register additional {@link org.springframework.beans.factory.config.BeanDefinition}s. + * @param meta The {@link AnnotationMetadata} to get additional properties for {@link BeanDefinition}s. + * @param registry The {@link BeanDefinitionRegistry} to register additional {@link BeanDefinition}s. */ private void registerMessagingAnnotationPostProcessors(AnnotationMetadata meta, BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME)) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class) - .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + BeanDefinitionBuilder builder = + BeanDefinitionBuilder.genericBeanDefinition(MessagingAnnotationPostProcessor.class) + .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME, builder.getBeanDefinition()); + registry.registerBeanDefinition(IntegrationContextUtils.MESSAGING_ANNOTATION_POSTPROCESSOR_NAME, + builder.getBeanDefinition()); } new PublisherRegistrar().registerBeanDefinitions(meta, registry); } /** - * Register {@link IntegrationConfigurationBeanFactoryPostProcessor} to process the external Integration infrastructure. + * Register {@link IntegrationConfigurationBeanFactoryPostProcessor} + * to process the external Integration infrastructure. */ private void registerIntegrationConfigurationBeanFactoryPostProcessor(BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME)) { BeanDefinitionBuilder postProcessorBuilder = BeanDefinitionBuilder .genericBeanDefinition(IntegrationConfigurationBeanFactoryPostProcessor.class) .setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME, postProcessorBuilder.getBeanDefinition()); + registry.registerBeanDefinition(IntegrationContextUtils.INTEGRATION_CONFIGURATION_POST_PROCESSOR_BEAN_NAME, + postProcessorBuilder.getBeanDefinition()); } } /** * Register the default datatype channel MessageConverter. - * * @param registry the registry. */ private void registerDefaultDatatypeChannelMessageConverter(BeanDefinitionRegistry registry) { diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java index 0da6259bff..8ae1ba0159 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractIntegrationNamespaceHandler.java @@ -52,7 +52,9 @@ public abstract class AbstractIntegrationNamespaceHandler implements NamespaceHa @Override public final BeanDefinition parse(Element element, ParserContext parserContext) { this.verifySchemaVersion(element, parserContext); - new IntegrationRegistrar().registerBeanDefinitions(null, parserContext.getRegistry()); + IntegrationRegistrar integrationRegistrar = new IntegrationRegistrar(); + integrationRegistrar.setBeanClassLoader(parserContext.getReaderContext().getBeanClassLoader()); + integrationRegistrar.registerBeanDefinitions(null, parserContext.getRegistry()); return this.delegate.parse(element, parserContext); } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java index 9c549fa0c7..1c6a679086 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/context/IntegrationContextUtils.java @@ -74,6 +74,9 @@ public abstract class IntegrationContextUtils { 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"; + /** * @param beanFactory BeanFactory for lookup, must not be null. * @return The {@link MetadataStore} bean whose name is "metadataStore". diff --git a/spring-integration-core/src/main/java/org/springframework/integration/json/ToStringFriendlyJsonNodeToStringConverter.java b/spring-integration-core/src/main/java/org/springframework/integration/json/ToStringFriendlyJsonNodeToStringConverter.java new file mode 100644 index 0000000000..d69f939c62 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/json/ToStringFriendlyJsonNodeToStringConverter.java @@ -0,0 +1,38 @@ +/* + * Copyright 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.json; + +import org.springframework.core.convert.converter.Converter; + +/** + * The {@link Converter} implementation for the conversion of + * {@link JsonPropertyAccessor.ToStringFriendlyJsonNode} to {@link String}, + * when the {@link JsonPropertyAccessor.ToStringFriendlyJsonNode} can be a result of the + * expression for JSON in case of the {@link JsonPropertyAccessor} usage. + * + * @author Artem Bilan + * @since 4.1 + */ +class ToStringFriendlyJsonNodeToStringConverter + implements Converter { + + @Override + public String convert(JsonPropertyAccessor.ToStringFriendlyJsonNode source) { + return source.toString(); + } + +} diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml index a7b4a4b1d5..dc2aa2e6be 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContext-context.xml @@ -34,4 +34,17 @@ + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java index 8926bb05af..a096f37ccd 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/expression/ParentContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.integration.expression; import static org.hamcrest.Matchers.instanceOf; @@ -30,6 +31,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import org.hamcrest.Matchers; import org.junit.Test; @@ -42,10 +44,12 @@ import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.config.IntegrationEvaluationContextFactoryBean; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.json.JsonPathUtils; +import org.springframework.integration.json.TestPerson; import org.springframework.integration.support.MutableMessageBuilder; import org.springframework.integration.test.util.TestUtils; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.PollableChannel; import org.springframework.messaging.support.GenericMessage; /** @@ -66,14 +70,19 @@ public class ParentContextTests { * and the parent's ones are last in the propertyAccessors list of EvaluationContext. * Verifies that SpEL functions are inherited from parent context and overridden with the same 'id'. * Verifies that child and parent contexts can have different message builders. + *

+ * Only single test method is allowed for 'ParentContext-context.xml', + * since it relies on static 'evalContexts' variable. */ @Test @SuppressWarnings("unchecked") public void testSpelBeanReferencesInChildAndParent() throws Exception { - AbstractApplicationContext parent = new ClassPathXmlApplicationContext("ParentContext-context.xml", this.getClass()); + AbstractApplicationContext parent = new ClassPathXmlApplicationContext("ParentContext-context.xml", + this.getClass()); Object parentEvaluationContextFactoryBean = parent.getBean(IntegrationEvaluationContextFactoryBean.class); - Map parentFunctions = TestUtils.getPropertyValue(parentEvaluationContextFactoryBean, "functions", Map.class); + Map parentFunctions = TestUtils.getPropertyValue(parentEvaluationContextFactoryBean, "functions", + Map.class); assertEquals(3, parentFunctions.size()); Object jsonPath = parentFunctions.get("jsonPath"); assertNotNull(jsonPath); @@ -84,7 +93,8 @@ public class ParentContextTests { child.refresh(); Object childEvaluationContextFactoryBean = child.getBean(IntegrationEvaluationContextFactoryBean.class); - Map childFunctions = TestUtils.getPropertyValue(childEvaluationContextFactoryBean, "functions", Map.class); + Map childFunctions = TestUtils.getPropertyValue(childEvaluationContextFactoryBean, "functions", + Map.class); assertEquals(4, childFunctions.size()); assertTrue(childFunctions.containsKey("barParent")); jsonPath = childFunctions.get("jsonPath"); @@ -101,7 +111,8 @@ public class ParentContextTests { assertTrue(propertyAccessors.contains(parentPropertyAccessor)); assertTrue(propertyAccessors.indexOf(parentPropertyAccessorOverride) > propertyAccessors.indexOf(parentPropertyAccessor)); - Map variables = (Map) TestUtils.getPropertyValue(evalContexts.get(0), "variables"); + Map variables = (Map) TestUtils.getPropertyValue(evalContexts.get(0), + "variables"); assertEquals(3, variables.size()); assertTrue(variables.containsKey("bar")); assertTrue(variables.containsKey("barParent")); @@ -161,6 +172,37 @@ public class ParentContextTests { assertEquals("org.springframework.integration.support.MutableMessage", out.getClass().getName()); assertEquals("FOO", out.getPayload()); + assertTrue(parent + .containsBean(IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME)); + + assertTrue(child + .containsBean(IntegrationContextUtils.TO_STRING_FRIENDLY_JSON_NODE_TO_STRING_CONVERTER_BEAN_NAME)); + + Object converterRegistrar = parent.getBean(IntegrationContextUtils.CONVERTER_REGISTRAR_BEAN_NAME); + assertNotNull(converterRegistrar); + Set converters = TestUtils.getPropertyValue(converterRegistrar, "converters", Set.class); + boolean toStringFriendlyJsonNodeToStringConverterPresent = false; + for (Object converter : converters) { + if ("ToStringFriendlyJsonNodeToStringConverter".equals(converter.getClass().getSimpleName())) { + toStringFriendlyJsonNodeToStringConverterPresent = true; + break; + } + } + + assertTrue(toStringFriendlyJsonNodeToStringConverterPresent); + + MessageChannel input = parent.getBean("testJsonNodeToStringConverterInputChannel", MessageChannel.class); + PollableChannel output = parent.getBean("testJsonNodeToStringConverterOutputChannel", PollableChannel.class); + + TestPerson person = new TestPerson(); + person.setFirstName("John"); + + input.send(new GenericMessage(person)); + + Message result = output.receive(1000); + assertNotNull(result); + assertEquals("JOHN", result.getPayload()); + child.close(); parent.close(); } @@ -180,5 +222,10 @@ public class ParentContextTests { return o; } + public String testJsonNodeToStringConverter(String payload) { + return payload.toUpperCase(); + } + } + } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/json/TestPerson.java b/spring-integration-core/src/test/java/org/springframework/integration/json/TestPerson.java index 467cbc9427..870fd5ae1a 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/json/TestPerson.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/json/TestPerson.java @@ -1,5 +1,5 @@ /* - * Copyright 2013 the original author or authors. + * Copyright 2013-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. @@ -20,7 +20,7 @@ package org.springframework.integration.json; * @author Mark Fisher * @since 2.0 */ -class TestPerson { +public class TestPerson { private volatile String firstName; @@ -30,7 +30,7 @@ class TestPerson { private volatile TestAddress address; - TestPerson() { + public TestPerson() { } public TestPerson(String firstName, String lastName, int age) { diff --git a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java index 04899044f2..2023927b45 100644 --- a/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java +++ b/spring-integration-file/src/main/java/org/springframework/integration/file/remote/gateway/AbstractRemoteFileOutboundGateway.java @@ -798,7 +798,10 @@ public abstract class AbstractRemoteFileOutboundGateway extends AbstractReply private File generateLocalDirectory(Message message, String remoteDirectory) { EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory()); evaluationContext.setVariable("remoteDirectory", remoteDirectory); - File localDir = this.localDirectoryExpression.getValue(evaluationContext, message, File.class); + //TODO see org.springframework.integration.context.CustomConversionServiceFactoryBean +// File localDir = this.localDirectoryExpression.getValue(evaluationContext, message, File.class); + String localDirPath = this.localDirectoryExpression.getValue(evaluationContext, message, String.class); + File localDir = new File(localDirPath); if (!localDir.exists()) { Assert.isTrue(localDir.mkdirs(), "Failed to make local directory: " + localDir); }