Browse Source

DATAJDBC-155 - Simplified construction of JdbcRepositoryFactory.

Made the DefaultDataAccessStrategy actually the default for JdbcRepositoryFactoryBean.
Therefore the injection of a strategy is optional.

Simplified constructors of DefaultDataAccessStrategy.
Created factory method to construct a correct DataAccessStrategy for use with MyBatis.

Did some untangling in the test application context configurations.

Original pull request: #54.
pull/44/merge
Jens Schauder 8 years ago committed by Christoph Strobl
parent
commit
aaae9a5f5c
  1. 11
      src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java
  2. 49
      src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java
  3. 4
      src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java
  4. 13
      src/main/java/org/springframework/data/jdbc/repository/support/JdbcRepositoryFactoryBean.java
  5. 1
      src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java
  6. 10
      src/test/java/org/springframework/data/jdbc/mybatis/MyBatisHsqlIntegrationTests.java
  7. 3
      src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java
  8. 28
      src/test/java/org/springframework/data/jdbc/testing/TestConfiguration.java

11
src/main/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategy.java

@ -56,11 +56,11 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
private final JdbcMappingContext context; private final JdbcMappingContext context;
private final DataAccessStrategy accessStrategy; private final DataAccessStrategy accessStrategy;
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, NamedParameterJdbcOperations operations, public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context,
JdbcMappingContext context, DataAccessStrategy accessStrategy) { DataAccessStrategy accessStrategy) {
this.sqlGeneratorSource = sqlGeneratorSource; this.sqlGeneratorSource = sqlGeneratorSource;
this.operations = operations; this.operations = context.getTemplate();
this.context = context; this.context = context;
this.accessStrategy = accessStrategy; this.accessStrategy = accessStrategy;
} }
@ -69,11 +69,10 @@ public class DefaultDataAccessStrategy implements DataAccessStrategy {
* Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses. * Creates a {@link DefaultDataAccessStrategy} which references it self for resolution of recursive data accesses.
* Only suitable if this is the only access strategy in use. * Only suitable if this is the only access strategy in use.
*/ */
public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, NamedParameterJdbcOperations operations, public DefaultDataAccessStrategy(SqlGeneratorSource sqlGeneratorSource, JdbcMappingContext context) {
JdbcMappingContext context) {
this.sqlGeneratorSource = sqlGeneratorSource; this.sqlGeneratorSource = sqlGeneratorSource;
this.operations = operations; this.operations = context.getTemplate();
this.context = context; this.context = context;
this.accessStrategy = this; this.accessStrategy = this;
} }

49
src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java

@ -15,15 +15,22 @@
*/ */
package org.springframework.data.jdbc.mybatis; package org.springframework.data.jdbc.mybatis;
import static java.util.Arrays.*;
import java.util.Collections;
import java.util.Map;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.data.jdbc.core.CascadingDataAccessStrategy;
import org.springframework.data.jdbc.core.DataAccessStrategy; import org.springframework.data.jdbc.core.DataAccessStrategy;
import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
import org.springframework.data.jdbc.core.DelegatingDataAccessStrategy;
import org.springframework.data.jdbc.core.SqlGeneratorSource;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty; import org.springframework.data.jdbc.mapping.model.JdbcPersistentProperty;
import org.springframework.data.mapping.PropertyPath; import org.springframework.data.mapping.PropertyPath;
import java.util.Collections;
import java.util.Map;
/** /**
* {@link DataAccessStrategy} implementation based on MyBatis. Each method gets mapped to a statement. The name of the * {@link DataAccessStrategy} implementation based on MyBatis. Each method gets mapped to a statement. The name of the
* statement gets constructed as follows: The namespace is based on the class of the entity plus the suffix "Mapper". * statement gets constructed as follows: The namespace is based on the class of the entity plus the suffix "Mapper".
@ -41,11 +48,43 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
private final SqlSession sqlSession; private final SqlSession sqlSession;
/**
* Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one
* used a {@link DefaultDataAccessStrategy}
*
* @param context
* @param sqlSession
* @return
*/
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) {
// the DefaultDataAccessStrategy needs a reference to the returned DataAccessStrategy. This creates a dependency
// cycle. In order to create it, we need something that allows to defer closing the cycle until all the elements are
// created. That is the purpose of the DelegatingAccessStrategy.
DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy();
MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession);
CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy(
asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy));
DefaultDataAccessStrategy defaultDataAccessStrategy = new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), //
context, //
cascadingDataAccessStrategy);
delegatingDataAccessStrategy.setDelegate(defaultDataAccessStrategy);
return cascadingDataAccessStrategy;
}
/** /**
* Constructs a {@link DataAccessStrategy} based on MyBatis. * Constructs a {@link DataAccessStrategy} based on MyBatis.
* <p> * <p>
* Use a {@link SqlSessionTemplate} for {@link SqlSession} or a similar implementation tying the session to the * Use a {@link SqlSessionTemplate} for {@link SqlSession} or a similar implementation tying the session to the proper
* proper transaction. * transaction. Note that the resulting {@link DataAccessStrategy} only handles MyBatis. It does not include the
* functionality of the {@link org.springframework.data.jdbc.core.DefaultDataAccessStrategy} which one normally still
* wants. Use {@link #createCombinedAccessStrategy(JdbcMappingContext, SqlSession)} to create such a
* {@link DataAccessStrategy}.
* *
* @param sqlSession Must be non {@literal null}. * @param sqlSession Must be non {@literal null}.
*/ */

4
src/main/java/org/springframework/data/jdbc/repository/config/JdbcConfiguration.java

@ -22,18 +22,20 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.data.jdbc.mapping.model.ConversionCustomizer; import org.springframework.data.jdbc.mapping.model.ConversionCustomizer;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext; import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.mapping.model.NamingStrategy; import org.springframework.data.jdbc.mapping.model.NamingStrategy;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
/** /**
* Beans that must be registered for Spring Data JDBC to work. * Beans that must be registered for Spring Data JDBC to work.
* *
* @author Greg Turnquist * @author Greg Turnquist
* @author Jens Schauder
*/ */
@Configuration @Configuration
public class JdbcConfiguration { public class JdbcConfiguration {
@Bean @Bean
JdbcMappingContext jdbcMappingContext(NamedParameterJdbcTemplate template, Optional<NamingStrategy> namingStrategy, JdbcMappingContext jdbcMappingContext(NamedParameterJdbcOperations template, Optional<NamingStrategy> namingStrategy,
Optional<ConversionCustomizer> conversionCustomizer) { Optional<ConversionCustomizer> conversionCustomizer) {
return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE), template, return new JdbcMappingContext(namingStrategy.orElse(NamingStrategy.INSTANCE), template,

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

@ -21,6 +21,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.jdbc.core.DataAccessStrategy; import org.springframework.data.jdbc.core.DataAccessStrategy;
import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
import org.springframework.data.jdbc.core.SqlGeneratorSource;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext; import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.repository.RowMapperMap; import org.springframework.data.jdbc.repository.RowMapperMap;
import org.springframework.data.repository.Repository; import org.springframework.data.repository.Repository;
@ -80,7 +82,7 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
this.mappingContext = mappingContext; this.mappingContext = mappingContext;
} }
@Autowired @Autowired(required = false)
public void setDataAccessStrategy(DataAccessStrategy dataAccessStrategy) { public void setDataAccessStrategy(DataAccessStrategy dataAccessStrategy) {
this.dataAccessStrategy = dataAccessStrategy; this.dataAccessStrategy = dataAccessStrategy;
} }
@ -93,8 +95,15 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
Assert.notNull(this.dataAccessStrategy, "DataAccessStrategy must not be null!");
Assert.notNull(this.mappingContext, "MappingContext must not be null!"); Assert.notNull(this.mappingContext, "MappingContext must not be null!");
if (dataAccessStrategy == null) {
dataAccessStrategy = new DefaultDataAccessStrategy( //
new SqlGeneratorSource(mappingContext), //
mappingContext);
}
super.afterPropertiesSet(); super.afterPropertiesSet();
} }
} }

1
src/test/java/org/springframework/data/jdbc/core/DefaultDataAccessStrategyUnitTests.java

@ -48,7 +48,6 @@ public class DefaultDataAccessStrategyUnitTests {
DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy( // DefaultDataAccessStrategy accessStrategy = new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), // new SqlGeneratorSource(context), //
jdbcOperations, //
context // context //
); );

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

@ -15,7 +15,7 @@
*/ */
package org.springframework.data.jdbc.mybatis; package org.springframework.data.jdbc.mybatis;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.*;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
@ -30,6 +30,8 @@ import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.data.jdbc.core.DataAccessStrategy;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories; import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.jdbc.testing.TestConfiguration;
import org.springframework.data.repository.CrudRepository; import org.springframework.data.repository.CrudRepository;
@ -39,8 +41,6 @@ import org.springframework.test.context.junit4.rules.SpringClassRule;
import org.springframework.test.context.junit4.rules.SpringMethodRule; import org.springframework.test.context.junit4.rules.SpringMethodRule;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import javax.net.ssl.SSLSocketFactory;
/** /**
* Tests the integration with Mybatis. * Tests the integration with Mybatis.
* *
@ -83,8 +83,8 @@ public class MyBatisHsqlIntegrationTests {
} }
@Bean @Bean
MyBatisDataAccessStrategy dataAccessStrategy(SqlSession sqlSession) { DataAccessStrategy dataAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) {
return new MyBatisDataAccessStrategy(sqlSession); return MyBatisDataAccessStrategy.createCombinedAccessStrategy(context, sqlSession);
} }
} }

3
src/test/java/org/springframework/data/jdbc/repository/SimpleJdbcRepositoryEventsUnitTests.java

@ -46,13 +46,12 @@ public class SimpleJdbcRepositoryEventsUnitTests {
@Before @Before
public void before() { public void before() {
final JdbcMappingContext context = new JdbcMappingContext(mock(NamedParameterJdbcOperations.class)); final JdbcMappingContext context = new JdbcMappingContext(createIdGeneratingOperations());
JdbcRepositoryFactory factory = new JdbcRepositoryFactory( // JdbcRepositoryFactory factory = new JdbcRepositoryFactory( //
publisher, // publisher, //
context, // context, //
new DefaultDataAccessStrategy( // new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), // new SqlGeneratorSource(context), //
createIdGeneratingOperations(), //
context // context //
) // ) //
); );

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

@ -21,14 +21,12 @@ import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.jdbc.core.DataAccessStrategy; import org.springframework.data.jdbc.core.DataAccessStrategy;
import org.springframework.data.jdbc.core.DefaultDataAccessStrategy; import org.springframework.data.jdbc.core.DefaultDataAccessStrategy;
import org.springframework.data.jdbc.core.DelegatingDataAccessStrategy;
import org.springframework.data.jdbc.core.SqlGeneratorSource; import org.springframework.data.jdbc.core.SqlGeneratorSource;
import org.springframework.data.jdbc.mapping.model.ConversionCustomizer; import org.springframework.data.jdbc.mapping.model.ConversionCustomizer;
import org.springframework.data.jdbc.mapping.model.JdbcMappingContext; import org.springframework.data.jdbc.mapping.model.JdbcMappingContext;
@ -54,24 +52,21 @@ public class TestConfiguration {
@Autowired(required = false) SqlSessionFactory sqlSessionFactory; @Autowired(required = false) SqlSessionFactory sqlSessionFactory;
@Bean @Bean
JdbcRepositoryFactory jdbcRepositoryFactory() { JdbcRepositoryFactory jdbcRepositoryFactory(DataAccessStrategy dataAccessStrategy) {
NamedParameterJdbcTemplate jdbcTemplate = namedParameterJdbcTemplate(); NamedParameterJdbcOperations jdbcTemplate = namedParameterJdbcTemplate();
final JdbcMappingContext context = new JdbcMappingContext(NamingStrategy.INSTANCE, jdbcTemplate, __ -> {}); final JdbcMappingContext context = new JdbcMappingContext(NamingStrategy.INSTANCE, jdbcTemplate, __ -> {});
return new JdbcRepositoryFactory( // return new JdbcRepositoryFactory( //
publisher, // publisher, //
context, // context, //
new DefaultDataAccessStrategy( // dataAccessStrategy //
new SqlGeneratorSource(context), //
jdbcTemplate, //
context) //
); );
} }
@Bean @Bean
NamedParameterJdbcTemplate namedParameterJdbcTemplate() { NamedParameterJdbcOperations namedParameterJdbcTemplate() {
return new NamedParameterJdbcTemplate(dataSource); return new NamedParameterJdbcTemplate(dataSource);
} }
@ -81,19 +76,8 @@ public class TestConfiguration {
} }
@Bean @Bean
DataAccessStrategy defaultDataAccessStrategy(JdbcMappingContext context, DataAccessStrategy defaultDataAccessStrategy(JdbcMappingContext context) {
@Qualifier("namedParameterJdbcTemplate") NamedParameterJdbcOperations operations) { return new DefaultDataAccessStrategy(new SqlGeneratorSource(context), context);
DelegatingDataAccessStrategy accessStrategy = new DelegatingDataAccessStrategy();
accessStrategy.setDelegate(new DefaultDataAccessStrategy( //
new SqlGeneratorSource(context), //
operations, //
context, //
accessStrategy) //
);
return accessStrategy;
} }
@Bean @Bean

Loading…
Cancel
Save