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**
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">
|
||||
|
||||
<import resource="classpath:/hibernateJpa-context.xml"/>
|
||||
|
||||
<int:channel id="out"/>
|
||||
|
||||
<bean id="jpaParameterSource" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="org.springframework.integration.jpa.support.parametersource.ParameterSource"/>
|
||||
</bean>
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter1"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
parameter-source="jpaParameterSource"
|
||||
auto-startup="false"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter2"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
max-results="13"
|
||||
delete-after-poll="true"
|
||||
flush-after-delete="true"
|
||||
auto-startup="false"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter3"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
max-results-expression="@maxNumberOfResults"
|
||||
auto-startup="false"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<bean name="maxNumberOfResults" class="java.lang.Integer">
|
||||
<constructor-arg value="2"/>
|
||||
</bean>
|
||||
|
||||
<int-jpa:inbound-channel-adapter
|
||||
channel="nullChannel"
|
||||
auto-startup="false"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
jpa-query="select rm from Msg rm where rm.isApproved= '1'">
|
||||
<int:poller fixed-rate="30000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<int-jpa:inbound-channel-adapter
|
||||
channel="nullChannel"
|
||||
auto-startup="false"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
jpa-query="select slt from Email slt where slt.mailStatus = 'NEW'">
|
||||
<int:poller fixed-rate="10000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
</beans>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">
|
||||
|
||||
<import resource="classpath:/hibernateJpa-context.xml" />
|
||||
|
||||
<int:channel id="out"/>
|
||||
|
||||
<bean id="jpaParameterSource" class="org.mockito.Mockito" factory-method="mock">
|
||||
<constructor-arg value="org.springframework.integration.jpa.support.parametersource.ParameterSource"/>
|
||||
</bean>
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter1"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
expect-single-result="true"
|
||||
parameter-source="jpaParameterSource"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter2"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
max-results="13"
|
||||
delete-after-poll="true"
|
||||
flush-after-delete="true"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<int-jpa:inbound-channel-adapter id="jpaInboundChannelAdapter3"
|
||||
entity-manager-factory="entityManagerFactory"
|
||||
entity-class="org.springframework.integration.jpa.test.entity.StudentDomain"
|
||||
max-results-expression="@maxNumberOfResults"
|
||||
channel="out">
|
||||
<int:poller fixed-rate="5000"/>
|
||||
</int-jpa:inbound-channel-adapter>
|
||||
|
||||
<bean name="maxNumberOfResults" class="java.lang.Integer">
|
||||
<constructor-arg value="2"/>
|
||||
</bean>
|
||||
</beans>
|
||||
Reference in New Issue
Block a user