diff --git a/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java b/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java index f56c5bc3f..6ae781565 100644 --- a/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java +++ b/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java @@ -30,14 +30,16 @@ 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.mapping.PropertyPath; +import org.springframework.util.Assert; /** * {@link DataAccessStrategy} implementation based on MyBatis. Each method gets mapped to a statement. The name of the - * statement gets constructed as follows: By default, the namespace is based on the class of the entity plus the suffix "Mapper". - * This is then followed by the method name separated by a dot. For methods taking a {@link PropertyPath} as argument, - * the relevant entity is that of the root of the path, and the path itself gets as dot separated String appended to the - * statement name. Each statement gets an instance of {@link MyBatisContext}, which at least has the entityType set. For - * methods taking a {@link PropertyPath} the entityTyoe if the context is set to the class of the leaf type. + * statement gets constructed as follows: By default, the namespace is based on the class of the entity plus the suffix + * "Mapper". This is then followed by the method name separated by a dot. For methods taking a {@link PropertyPath} as + * argument, the relevant entity is that of the root of the path, and the path itself gets as dot separated String + * appended to the statement name. Each statement gets an instance of {@link MyBatisContext}, which at least has the + * entityType set. For methods taking a {@link PropertyPath} the entityTyoe if the context is set to the class of the + * leaf type. * * @author Jens Schauder * @author Kazuki Shimizu @@ -45,23 +47,29 @@ import org.springframework.data.mapping.PropertyPath; public class MyBatisDataAccessStrategy implements DataAccessStrategy { private final SqlSession sqlSession; - private MyBatisNamingStrategy namingStrategy = new MyBatisNamingStrategy() {}; + private NamespaceStrategy namespaceStrategy = NamespaceStrategy.DEFAULT_INSTANCE; /** * 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 + * uses a {@link DefaultDataAccessStrategy} */ public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) { + return createCombinedAccessStrategy(context, sqlSession, NamespaceStrategy.DEFAULT_INSTANCE); + } + + /** + * Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one + * uses a {@link DefaultDataAccessStrategy} + */ + public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession, + NamespaceStrategy namespaceStrategy) { // 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); + myBatisDataAccessStrategy.setNamespaceStrategy(namespaceStrategy); CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy( asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy)); @@ -92,11 +100,15 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy { } /** - * Set a naming strategy for MyBatis objects. - * @param namingStrategy Must be non {@literal null} + * Set a NamespaceStrategy to be used. + * + * @param namespaceStrategy Must be non {@literal null} */ - public void setNamingStrategy(MyBatisNamingStrategy namingStrategy) { - this.namingStrategy = namingStrategy; + public void setNamespaceStrategy(NamespaceStrategy namespaceStrategy) { + + Assert.notNull(namespaceStrategy, "The NamespaceStrategy must not be null"); + + this.namespaceStrategy = namespaceStrategy; } @Override @@ -168,7 +180,8 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy { @Override public Iterable findAllByProperty(Object rootId, JdbcPersistentProperty property) { - return sqlSession().selectList(namespace(property.getOwner().getType()) + ".findAllByProperty-" + property.getName(), + return sqlSession().selectList( + namespace(property.getOwner().getType()) + ".findAllByProperty-" + property.getName(), new MyBatisContext(rootId, null, property.getType(), Collections.emptyMap())); } @@ -185,7 +198,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy { } private String namespace(Class domainType) { - return this.namingStrategy.getNamespace(domainType); + return this.namespaceStrategy.getNamespace(domainType); } private SqlSession sqlSession() { diff --git a/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisNamingStrategy.java b/src/main/java/org/springframework/data/jdbc/mybatis/NamespaceStrategy.java similarity index 79% rename from src/main/java/org/springframework/data/jdbc/mybatis/MyBatisNamingStrategy.java rename to src/main/java/org/springframework/data/jdbc/mybatis/NamespaceStrategy.java index 89c23cb73..936038699 100644 --- a/src/main/java/org/springframework/data/jdbc/mybatis/MyBatisNamingStrategy.java +++ b/src/main/java/org/springframework/data/jdbc/mybatis/NamespaceStrategy.java @@ -16,16 +16,20 @@ package org.springframework.data.jdbc.mybatis; /** - * The naming strategy for MyBatis. + * A strategy to derive a MyBatis namespace from a domainType. * * @author Kazuki Shimizu + * @author Jens Schauder */ -public interface MyBatisNamingStrategy { +public interface NamespaceStrategy { + + NamespaceStrategy DEFAULT_INSTANCE = new NamespaceStrategy() {}; /** - * Get a namespace that correspond domain type. + * Get a namespace that corresponds to the given domain type. *

* By default, the namespace is based on the class of the entity plus the suffix "Mapper". + * * @param domainType Must be non {@literal null}. * @return a namespace that correspond domain type */ diff --git a/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java index b74835edd..46a8d2a14 100644 --- a/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java +++ b/src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java @@ -15,12 +15,12 @@ */ package org.springframework.data.jdbc.mybatis; -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; +import static org.assertj.core.api.Assertions.*; import junit.framework.AssertionFailedError; +import java.io.IOException; + import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; @@ -38,20 +38,39 @@ import org.springframework.data.jdbc.testing.TestConfiguration; import org.springframework.data.repository.CrudRepository; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.junit4.rules.SpringClassRule; import org.springframework.test.context.junit4.rules.SpringMethodRule; import org.springframework.transaction.annotation.Transactional; /** - * Tests the integration for customizing namespace with Mybatis. + * Tests the integration for customizing the namespace with Mybatis. * * @author Kazuki Shimizu + * @author Jens Schauder */ @ContextConfiguration @Transactional public class MyBatisCustomizingNamespaceHsqlIntegrationTests { + @ClassRule public static final SpringClassRule classRule = new SpringClassRule(); + @Rule public SpringMethodRule methodRule = new SpringMethodRule(); + + @Autowired SqlSessionFactory sqlSessionFactory; + @Autowired DummyEntityRepository repository; + + @Test // DATAJDBC-178 + public void myBatisGetsUsedForInsertAndSelect() { + + DummyEntity entity = new DummyEntity(null, "some name"); + DummyEntity saved = repository.save(entity); + + assertThat(saved.id).isNotNull(); + + DummyEntity reloaded = repository.findById(saved.id).orElseThrow(AssertionFailedError::new); + + assertThat(reloaded.name).isEqualTo("name " + saved.id); + } + @org.springframework.context.annotation.Configuration @Import(TestConfiguration.class) @EnableJdbcRepositories(considerNestedRepositories = true) @@ -85,37 +104,19 @@ public class MyBatisCustomizingNamespaceHsqlIntegrationTests { @Bean MyBatisDataAccessStrategy dataAccessStrategy(SqlSession sqlSession) { + MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession); - strategy.setNamingStrategy(new MyBatisNamingStrategy() { + + strategy.setNamespaceStrategy(new NamespaceStrategy() { @Override public String getNamespace(Class domainType) { return domainType.getPackage().getName() + ".mapper." + domainType.getSimpleName() + "Mapper"; } }); + return strategy; } } - @ClassRule public static final SpringClassRule classRule = new SpringClassRule(); - @Rule public SpringMethodRule methodRule = new SpringMethodRule(); - - @Autowired SqlSessionFactory sqlSessionFactory; - @Autowired DummyEntityRepository repository; - - @Test // DATAJDBC-178 - public void myBatisGetsUsedForInsertAndSelect() { - - DummyEntity entity = new DummyEntity(null, "some name"); - DummyEntity saved = repository.save(entity); - - assertThat(saved.id).isNotNull(); - - DummyEntity reloaded = repository.findById(saved.id).orElseThrow(AssertionFailedError::new); - - assertThat(reloaded.name).isEqualTo("name " + saved.id); - } - - interface DummyEntityRepository extends CrudRepository { - } - + interface DummyEntityRepository extends CrudRepository {} }