From cb1784d9786e8aaa470761cd1c3aac1ed93be8fc Mon Sep 17 00:00:00 2001 From: Artem Bilan Date: Fri, 4 Aug 2017 20:30:13 -0400 Subject: [PATCH] INT-4325: Fix JpaExecutor bean registration JIRA: https://jira.spring.io/browse/INT-4325 When channel adapter is defined without `id` attribute, the `JpaInboundChannelAdapterParser` generates the name for class which bean is never registered, therefore all the `JpaExecutor`s are registered with the same bean name and afterward all the `JpaPollingChannelAdapter` without `id` share the same `JpaExecutor` * Generate bean name based on the `SourcePollingChannelAdapterFactoryBean` which is used eventually for real bean registration * Add test config for several channel adapters without `id` * Optimize the `JpaInboundChannelAdapterParserTests` to start the context only once during test class initialization **Cherry-pick to 4.3.x** --- .../xml/JpaInboundChannelAdapterParser.java | 30 ++++--- ...boundChannelAdapterParserTests-context.xml | 68 ++++++++++++++ .../JpaInboundChannelAdapterParserTests.java | 88 +++++++++++-------- .../JpaInboundChannelAdapterParserTests.xml | 50 ----------- 4 files changed, 135 insertions(+), 101 deletions(-) create mode 100644 spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests-context.xml delete mode 100644 spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.xml diff --git a/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParser.java b/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParser.java index ce7b4027ef..515a1a5fab 100644 --- a/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParser.java +++ b/spring-integration-jpa/src/main/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-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. @@ -22,7 +22,9 @@ import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean; import org.springframework.integration.config.xml.AbstractPollingInboundChannelAdapterParser; import org.springframework.integration.config.xml.IntegrationNamespaceUtils; import org.springframework.integration.jpa.inbound.JpaPollingChannelAdapter; @@ -33,21 +35,21 @@ import org.springframework.integration.jpa.inbound.JpaPollingChannelAdapter; * @author Amol Nayak * @author Gunnar Hillert * @author Artem Bilan + * * @since 2.2 */ public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChannelAdapterParser { @Override protected BeanMetadataElement parseSource(Element element, ParserContext parserContext) { + BeanDefinitionBuilder jpaPollingChannelAdapterBuilder = + BeanDefinitionBuilder.genericBeanDefinition(JpaPollingChannelAdapter.class); - final BeanDefinitionBuilder jpaPollingChannelAdapterBuilder = BeanDefinitionBuilder - .genericBeanDefinition(JpaPollingChannelAdapter.class); + BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(element, parserContext); - final BeanDefinitionBuilder jpaExecutorBuilder = JpaParserUtils.getJpaExecutorBuilder(element, parserContext); - - BeanDefinition definition = IntegrationNamespaceUtils - .createExpressionDefinitionFromValueOrExpression("max-results", "max-results-expression", - parserContext, element, false); + BeanDefinition definition = + IntegrationNamespaceUtils.createExpressionDefinitionFromValueOrExpression("max-results", + "max-results-expression", parserContext, element, false); if (definition != null) { jpaExecutorBuilder.addPropertyValue("maxResultsExpression", definition); } @@ -57,11 +59,15 @@ public class JpaInboundChannelAdapterParser extends AbstractPollingInboundChanne IntegrationNamespaceUtils.setValueIfAttributeDefined(jpaExecutorBuilder, element, "expect-single-result"); IntegrationNamespaceUtils.setReferenceIfAttributeDefined(jpaExecutorBuilder, element, "parameter-source"); - final BeanDefinition jpaExecutorBuilderBeanDefinition = jpaExecutorBuilder.getBeanDefinition(); - final String channelAdapterId = this.resolveId(element, jpaPollingChannelAdapterBuilder.getRawBeanDefinition(), parserContext); - final String jpaExecutorBeanName = channelAdapterId + ".jpaExecutor"; + BeanDefinition jpaExecutorBuilderBeanDefinition = jpaExecutorBuilder.getBeanDefinition(); + String channelAdapterId = + resolveId(element, + new RootBeanDefinition(SourcePollingChannelAdapterFactoryBean.class), + parserContext); + String jpaExecutorBeanName = channelAdapterId + ".jpaExecutor"; - parserContext.registerBeanComponent(new BeanComponentDefinition(jpaExecutorBuilderBeanDefinition, jpaExecutorBeanName)); + parserContext.registerBeanComponent(new BeanComponentDefinition(jpaExecutorBuilderBeanDefinition, + jpaExecutorBeanName)); jpaPollingChannelAdapterBuilder.addConstructorArgReference(jpaExecutorBeanName); diff --git a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests-context.xml b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests-context.xml new file mode 100644 index 0000000000..9ceaf63c9f --- /dev/null +++ b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests-context.xml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.java b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.java index 5c4c54ca64..19a7173f03 100644 --- a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.java +++ b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-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. @@ -18,14 +18,15 @@ package org.springframework.integration.jpa.config.xml; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import org.junit.After; import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.expression.common.LiteralExpression; import org.springframework.expression.spel.standard.SpelExpression; import org.springframework.integration.channel.AbstractMessageChannel; @@ -34,6 +35,8 @@ import org.springframework.integration.jpa.core.JpaExecutor; import org.springframework.integration.jpa.core.JpaOperations; import org.springframework.integration.jpa.support.parametersource.ParameterSource; import org.springframework.integration.test.util.TestUtils; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.junit4.SpringRunner; /** * @author Gunnar Hillert @@ -43,30 +46,39 @@ import org.springframework.integration.test.util.TestUtils; * @since 2.2 * */ +@RunWith(SpringRunner.class) +@DirtiesContext public class JpaInboundChannelAdapterParserTests { + @Autowired private ConfigurableApplicationContext context; - private SourcePollingChannelAdapter consumer; + @Autowired + private SourcePollingChannelAdapter jpaInboundChannelAdapter1; + + @Autowired + private SourcePollingChannelAdapter jpaInboundChannelAdapter2; + + @Autowired + private SourcePollingChannelAdapter jpaInboundChannelAdapter3; @Test public void testJpaInboundChannelAdapterParser() throws Exception { - - setUp("JpaInboundChannelAdapterParserTests.xml", getClass(), "jpaInboundChannelAdapter1"); - - final AbstractMessageChannel outputChannel = TestUtils.getPropertyValue(this.consumer, "outputChannel", AbstractMessageChannel.class); + AbstractMessageChannel outputChannel = + TestUtils.getPropertyValue(this.jpaInboundChannelAdapter1, "outputChannel", AbstractMessageChannel.class); assertEquals("out", outputChannel.getComponentName()); - final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "source.jpaExecutor", JpaExecutor.class); + JpaExecutor jpaExecutor = + TestUtils.getPropertyValue(this.jpaInboundChannelAdapter1, "source.jpaExecutor", JpaExecutor.class); assertNotNull(jpaExecutor); - final Class entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class); + Class entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class); assertEquals("org.springframework.integration.jpa.test.entity.StudentDomain", entityClass.getName()); - final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class); + JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class); assertNotNull(jpaOperations); @@ -77,22 +89,21 @@ public class JpaInboundChannelAdapterParserTests { @Test public void testJpaInboundChannelAdapterParserWithMaxResults() throws Exception { - - setUp("JpaInboundChannelAdapterParserTests.xml", getClass(), "jpaInboundChannelAdapter2"); - - final AbstractMessageChannel outputChannel = TestUtils.getPropertyValue(this.consumer, "outputChannel", AbstractMessageChannel.class); + AbstractMessageChannel outputChannel = + TestUtils.getPropertyValue(this.jpaInboundChannelAdapter2, "outputChannel", AbstractMessageChannel.class); assertEquals("out", outputChannel.getComponentName()); - final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "source.jpaExecutor", JpaExecutor.class); + JpaExecutor jpaExecutor = + TestUtils.getPropertyValue(this.jpaInboundChannelAdapter2, "source.jpaExecutor", JpaExecutor.class); assertNotNull(jpaExecutor); - final Class entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class); + Class entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class); assertEquals("org.springframework.integration.jpa.test.entity.StudentDomain", entityClass.getName()); - final JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class); + JpaOperations jpaOperations = TestUtils.getPropertyValue(jpaExecutor, "jpaOperations", JpaOperations.class); assertNotNull(jpaOperations); @@ -108,18 +119,17 @@ public class JpaInboundChannelAdapterParserTests { @Test public void testJpaInboundChannelAdapterParserWithMaxResultsExpression() throws Exception { - - setUp("JpaInboundChannelAdapterParserTests.xml", getClass(), "jpaInboundChannelAdapter3"); - - final AbstractMessageChannel outputChannel = TestUtils.getPropertyValue(this.consumer, "outputChannel", AbstractMessageChannel.class); + AbstractMessageChannel outputChannel = + TestUtils.getPropertyValue(this.jpaInboundChannelAdapter3, "outputChannel", AbstractMessageChannel.class); assertEquals("out", outputChannel.getComponentName()); - final JpaExecutor jpaExecutor = TestUtils.getPropertyValue(this.consumer, "source.jpaExecutor", JpaExecutor.class); + JpaExecutor jpaExecutor = + TestUtils.getPropertyValue(this.jpaInboundChannelAdapter3, "source.jpaExecutor", JpaExecutor.class); assertNotNull(jpaExecutor); - final Class entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class); + Class entityClass = TestUtils.getPropertyValue(jpaExecutor, "entityClass", Class.class); assertEquals("org.springframework.integration.jpa.test.entity.StudentDomain", entityClass.getName()); @@ -132,30 +142,30 @@ public class JpaInboundChannelAdapterParserTests { assertNotNull(expression); assertEquals("@maxNumberOfResults", TestUtils.getPropertyValue(expression, "expression")); - } @Test public void testJpaExecutorBeanIdNaming() throws Exception { + JpaExecutor jpaExecutor1 = this.context.getBean("jpaInboundChannelAdapter1.jpaExecutor", JpaExecutor.class); + JpaExecutor jpaExecutor2 = this.context.getBean("jpaInboundChannelAdapter2.jpaExecutor", JpaExecutor.class); - this.context = new ClassPathXmlApplicationContext("JpaInboundChannelAdapterParserTests.xml", getClass()); + assertNotNull(jpaExecutor1); + assertNotNull(jpaExecutor2); + assertNotSame(jpaExecutor1, jpaExecutor2); - assertNotNull(context.getBean("jpaInboundChannelAdapter1.jpaExecutor", JpaExecutor.class)); - assertNotNull(context.getBean("jpaInboundChannelAdapter2.jpaExecutor", JpaExecutor.class)); + assertEquals(5, this.context.getBeansOfType(JpaExecutor.class).size()); - } + JpaExecutor jpaExecutorWithoutId0 = + this.context.getBean("org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0.jpaExecutor", + JpaExecutor.class); + JpaExecutor jpaExecutorWithoutId1 = + this.context.getBean("org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#1.jpaExecutor", + JpaExecutor.class); - @After - public void tearDown() { - if (context != null) { - context.close(); - } - } - - public void setUp(String name, Class cls, String consumerId) { - context = new ClassPathXmlApplicationContext(name, cls); - consumer = this.context.getBean(consumerId, SourcePollingChannelAdapter.class); + assertNotNull(jpaExecutorWithoutId0); + assertNotNull(jpaExecutorWithoutId1); + assertNotSame(jpaExecutorWithoutId0, jpaExecutorWithoutId1); } } diff --git a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.xml b/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.xml deleted file mode 100644 index a93a1996d5..0000000000 --- a/spring-integration-jpa/src/test/java/org/springframework/integration/jpa/config/xml/JpaInboundChannelAdapterParserTests.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -