Skip to content

Commit b20ccf0

Browse files
committed
DATAJDBC-293 @EnableJdbcRepositories support multi jdbcTemplate
1 parent a4fcaa5 commit b20ccf0

File tree

7 files changed

+123
-16
lines changed

7 files changed

+123
-16
lines changed

src/main/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositories.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,17 @@
9797
* for {@code PersonRepositoryImpl}.
9898
*/
9999
String repositoryImplementationPostfix() default "Impl";
100+
101+
/**
102+
* Configures the name of the {@link NamedParameterJdbcOperations} bean definition to be used to create repositories
103+
* discovered through this annotation. Defaults to {@code namedParameterJdbcTemplate}.
104+
*/
105+
String jdbcOperationsRef() default "namedParameterJdbcTemplate";
106+
107+
108+
/**
109+
* Configures the name of the {@link DataAccessStrategy} bean definition to be used to create repositories
110+
* discovered through this annotation. Defaults to {@code defaultDataAccessStrategy} if existed.
111+
*/
112+
String dataAccessStrategyRef() default "";
100113
}

src/main/java/org/springframework/data/jdbc/repository/config/JdbcRepositoryConfigExtension.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,21 @@
1515
*/
1616
package org.springframework.data.jdbc.repository.config;
1717

18+
import java.util.Arrays;
19+
import java.util.List;
1820
import java.util.Locale;
21+
import java.util.Optional;
1922

23+
import org.springframework.beans.factory.ListableBeanFactory;
24+
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
25+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
26+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
27+
import org.springframework.data.jdbc.core.DataAccessStrategy;
2028
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean;
29+
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
2130
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
31+
import org.springframework.data.repository.config.RepositoryConfigurationSource;
32+
import org.springframework.util.StringUtils;
2233

2334
/**
2435
* {@link org.springframework.data.repository.config.RepositoryConfigurationExtension} extending the repository
@@ -28,6 +39,10 @@
2839
*/
2940
public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {
3041

42+
private static final String DEFAULT_JDBC_OPERATION_BEAN_NAME = "namedParameterJdbcTemplate";
43+
44+
45+
private ListableBeanFactory listableBeanFactory;
3146
/*
3247
* (non-Javadoc)
3348
* @see org.springframework.data.repository.config.RepositoryConfigurationExtension#getModuleName()
@@ -36,6 +51,7 @@ public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtens
3651
public String getModuleName() {
3752
return "JDBC";
3853
}
54+
3955

4056
/*
4157
* (non-Javadoc)
@@ -55,4 +71,42 @@ protected String getModulePrefix() {
5571
return getModuleName().toLowerCase(Locale.US);
5672
}
5773

74+
/*
75+
* (non-Javadoc)
76+
* @see org.springframework.data.repository.config.RepositoryConfigurationExtension#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource)
77+
*/
78+
public void registerBeansForRoot(BeanDefinitionRegistry registry,
79+
RepositoryConfigurationSource configurationSource) {
80+
if (registry instanceof ListableBeanFactory) {
81+
this.listableBeanFactory = (ListableBeanFactory) registry;
82+
}
83+
}
84+
85+
86+
/*
87+
* (non-Javadoc)
88+
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.RepositoryConfigurationSource)
89+
*/
90+
@Override
91+
public void postProcess(BeanDefinitionBuilder builder, RepositoryConfigurationSource source) {
92+
93+
Optional<String> jdbcOperationRef = source.getAttribute("jdbcOperationsRef");
94+
builder.addPropertyReference("jdbcOperations", jdbcOperationRef.orElse(DEFAULT_JDBC_OPERATION_BEAN_NAME));
95+
Optional<String> dataAccessStrategyRef = source.getAttribute("dataAccessStrategyRef").filter(StringUtils::hasText);
96+
if (dataAccessStrategyRef.isPresent()) {
97+
builder.addPropertyReference("dataAccessStrategy", dataAccessStrategyRef.get());
98+
} else if(this.listableBeanFactory != null) {
99+
List<String> beanNames=Arrays.asList(listableBeanFactory.getBeanNamesForType(DataAccessStrategy.class));
100+
101+
if (beanNames.size() > 1) {
102+
throw new NoUniqueBeanDefinitionException(DataAccessStrategy.class, beanNames);
103+
}
104+
105+
if (!beanNames.isEmpty()) {
106+
builder.addPropertyReference("dataAccessStrategy", beanNames.get(0));
107+
}
108+
109+
}
110+
}
111+
58112
}

src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ public void setRowMapperMap(RowMapperMap rowMapperMap) {
110110
this.rowMapperMap = rowMapperMap;
111111
}
112112

113-
@Autowired
114113
public void setJdbcOperations(NamedParameterJdbcOperations operations) {
115114
this.operations = operations;
116115
}

src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public void myBatisGetsUsedForInsertAndSelect() {
7575

7676
@org.springframework.context.annotation.Configuration
7777
@Import(TestConfiguration.class)
78-
@EnableJdbcRepositories(considerNestedRepositories = true)
78+
@EnableJdbcRepositories(considerNestedRepositories = true, dataAccessStrategyRef="myBatisDataAccessStrategy")
7979
static class Config {
8080

8181
@Bean
@@ -104,7 +104,7 @@ SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory factory) {
104104
return new SqlSessionTemplate(factory);
105105
}
106106

107-
@Bean
107+
@Bean("myBatisDataAccessStrategy")
108108
MyBatisDataAccessStrategy dataAccessStrategy(SqlSession sqlSession) {
109109

110110
MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession);

src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public class MyBatisHsqlIntegrationTests {
5858

5959
@org.springframework.context.annotation.Configuration
6060
@Import(TestConfiguration.class)
61-
@EnableJdbcRepositories(considerNestedRepositories = true)
61+
@EnableJdbcRepositories(considerNestedRepositories = true, dataAccessStrategyRef = "myBatisDataAccessStrategy")
6262
static class Config {
6363

6464
@Bean
@@ -87,7 +87,7 @@ SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory factory) {
8787
return new SqlSessionTemplate(factory);
8888
}
8989

90-
@Bean
90+
@Bean("myBatisDataAccessStrategy")
9191
DataAccessStrategy dataAccessStrategy(RelationalMappingContext context, RelationalConverter converter,
9292
SqlSession sqlSession, EmbeddedDatabase db) {
9393
return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, converter,

src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcRepositoriesIntegrationTests.java

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,40 @@
1515
*/
1616
package org.springframework.data.jdbc.repository.config;
1717

18-
import static org.assertj.core.api.Assertions.*;
19-
import static org.mockito.Mockito.*;
20-
21-
import lombok.Data;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.mockito.Mockito.mock;
2220

2321
import java.lang.reflect.Field;
2422

23+
import javax.sql.DataSource;
24+
2525
import org.junit.BeforeClass;
2626
import org.junit.Test;
2727
import org.junit.runner.RunWith;
2828
import org.springframework.beans.factory.annotation.Autowired;
29+
import org.springframework.beans.factory.annotation.Qualifier;
2930
import org.springframework.context.annotation.Bean;
3031
import org.springframework.context.annotation.ComponentScan;
3132
import org.springframework.context.annotation.FilterType;
3233
import org.springframework.data.annotation.Id;
34+
import org.springframework.data.jdbc.core.DataAccessStrategy;
35+
import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
36+
import org.springframework.data.jdbc.core.SqlGeneratorSource;
3337
import org.springframework.data.jdbc.repository.RowMapperMap;
3438
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositoriesIntegrationTests.TestConfiguration;
3539
import org.springframework.data.jdbc.repository.support.JdbcRepositoryFactoryBean;
40+
import org.springframework.data.relational.core.conversion.RelationalConverter;
41+
import org.springframework.data.relational.core.mapping.RelationalMappingContext;
3642
import org.springframework.data.repository.CrudRepository;
3743
import org.springframework.jdbc.core.RowMapper;
44+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
45+
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
3846
import org.springframework.test.context.ContextConfiguration;
3947
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
4048
import org.springframework.util.ReflectionUtils;
4149

50+
import lombok.Data;
51+
4252
/**
4353
* Tests the {@link EnableJdbcRepositories} annotation.
4454
*
@@ -50,15 +60,23 @@
5060
public class EnableJdbcRepositoriesIntegrationTests {
5161

5262
static final Field ROW_MAPPER_MAP = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "rowMapperMap");
63+
static final Field OPERATIONS = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "operations");
64+
static final Field DATA_ACCESS_STRATEGY = ReflectionUtils.findField(JdbcRepositoryFactoryBean.class, "dataAccessStrategy");
5365
public static final RowMapper DUMMY_ENTITY_ROW_MAPPER = mock(RowMapper.class);
5466
public static final RowMapper STRING_ROW_MAPPER = mock(RowMapper.class);
5567

5668
@Autowired JdbcRepositoryFactoryBean factoryBean;
5769
@Autowired DummyRepository repository;
70+
@Autowired @Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations defaultOperations;
71+
@Autowired @Qualifier("defaultDataAccessStrategy") DataAccessStrategy defaultDataAccessStrategy;
72+
@Autowired @Qualifier("qualifierJdbcOperations") NamedParameterJdbcOperations qualifierJdbcOperations;
73+
@Autowired @Qualifier("qualifierDataAccessStrategy") DataAccessStrategy qualifierDataAccessStrategy;
5874

5975
@BeforeClass
6076
public static void setup() {
6177
ROW_MAPPER_MAP.setAccessible(true);
78+
OPERATIONS.setAccessible(true);
79+
DATA_ACCESS_STRATEGY.setAccessible(true);
6280
}
6381

6482
@Test // DATAJDBC-100
@@ -80,6 +98,15 @@ public void customRowMapperConfigurationGetsPickedUp() {
8098
assertThat(mapping.rowMapperFor(DummyEntity.class)).isEqualTo(DUMMY_ENTITY_ROW_MAPPER);
8199
}
82100

101+
@Test // DATAJDBC-293
102+
public void jdbcOperationsRef() {
103+
NamedParameterJdbcOperations operations = (NamedParameterJdbcOperations) ReflectionUtils.getField(OPERATIONS, factoryBean);
104+
assertThat(operations).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierJdbcOperations);
105+
106+
DataAccessStrategy dataAccessStrategy = (DataAccessStrategy) ReflectionUtils.getField(DATA_ACCESS_STRATEGY, factoryBean);
107+
assertThat(dataAccessStrategy).isNotSameAs(defaultDataAccessStrategy).isSameAs(qualifierDataAccessStrategy);
108+
}
109+
83110
interface DummyRepository extends CrudRepository<DummyEntity, Long> {
84111

85112
}
@@ -90,7 +117,9 @@ static class DummyEntity {
90117
}
91118

92119
@ComponentScan("org.springframework.data.jdbc.testing")
93-
@EnableJdbcRepositories(considerNestedRepositories = true, includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DummyRepository.class))
120+
@EnableJdbcRepositories(considerNestedRepositories = true,
121+
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DummyRepository.class),
122+
jdbcOperationsRef = "qualifierJdbcOperations", dataAccessStrategyRef = "qualifierDataAccessStrategy")
94123
static class TestConfiguration {
95124

96125
@Bean
@@ -105,5 +134,15 @@ RowMapperMap rowMappers() {
105134
.register(String.class, STRING_ROW_MAPPER);
106135
}
107136

137+
@Bean("qualifierJdbcOperations")
138+
NamedParameterJdbcOperations qualifierJdbcOperations(DataSource dataSource) {
139+
return new NamedParameterJdbcTemplate(dataSource);
140+
}
141+
142+
@Bean("qualifierDataAccessStrategy")
143+
DataAccessStrategy defaultDataAccessStrategy(@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template,
144+
RelationalMappingContext context, RelationalConverter converter) {
145+
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, converter, template);
146+
}
108147
}
109148
}

src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121

2222
import org.apache.ibatis.session.SqlSessionFactory;
2323
import org.springframework.beans.factory.annotation.Autowired;
24+
import org.springframework.beans.factory.annotation.Qualifier;
2425
import org.springframework.context.ApplicationEventPublisher;
2526
import org.springframework.context.annotation.Bean;
2627
import org.springframework.context.annotation.ComponentScan;
2728
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.context.annotation.Primary;
2830
import org.springframework.data.convert.CustomConversions;
2931
import org.springframework.data.jdbc.core.DataAccessStrategy;
3032
import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
@@ -56,8 +58,8 @@ public class TestConfiguration {
5658
@Autowired(required = false) SqlSessionFactory sqlSessionFactory;
5759

5860
@Bean
59-
JdbcRepositoryFactory jdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy, RelationalMappingContext context,
60-
RelationalConverter converter) {
61+
JdbcRepositoryFactory jdbcRepositoryFactory(@Qualifier("defaultDataAccessStrategy") DataAccessStrategy dataAccessStrategy,
62+
RelationalMappingContext context, RelationalConverter converter) {
6163
return new JdbcRepositoryFactory(dataAccessStrategy, context, converter, publisher, namedParameterJdbcTemplate());
6264
}
6365

@@ -72,13 +74,13 @@ PlatformTransactionManager transactionManager() {
7274
}
7375

7476
@Bean
75-
DataAccessStrategy defaultDataAccessStrategy(RelationalMappingContext context, RelationalConverter converter) {
76-
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, converter,
77-
namedParameterJdbcTemplate());
77+
DataAccessStrategy defaultDataAccessStrategy(@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template,
78+
RelationalMappingContext context, RelationalConverter converter) {
79+
return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context, converter,template);
7880
}
7981

8082
@Bean
81-
RelationalMappingContext jdbcMappingContext(NamedParameterJdbcOperations template,
83+
RelationalMappingContext jdbcMappingContext(@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations template,
8284
Optional<NamingStrategy> namingStrategy, CustomConversions conversions) {
8385

8486
RelationalMappingContext mappingContext = new RelationalMappingContext(

0 commit comments

Comments
 (0)