Browse Source

DATAJDBC-178 - Polishing.

Renamed MyBatisNamingStrategy into NamespaceStrategy.
This avoids the confusion with the existing NamingStrategy.

Introduced a default instance.
Added a method creating a proper DataAccessStrategy with a NamespaceStrategy.

JavaDoc.

Original pull request: #44.
pull/56/head
Jens Schauder 8 years ago
parent
commit
c7958f82a3
  1. 47
      src/main/java/org/springframework/data/jdbc/mybatis/MyBatisDataAccessStrategy.java
  2. 10
      src/main/java/org/springframework/data/jdbc/mybatis/NamespaceStrategy.java
  3. 57
      src/test/java/org/springframework/data/jdbc/mybatis/MyBatisCustomizingNamespaceHsqlIntegrationTests.java

47
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.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 org.springframework.util.Assert;
/** /**
* {@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: By default, the namespace is based on the class of the entity plus the suffix "Mapper". * statement gets constructed as follows: By default, the namespace is based on the class of the entity plus the suffix
* This is then followed by the method name separated by a dot. For methods taking a {@link PropertyPath} as argument, * "Mapper". This is then followed by the method name separated by a dot. For methods taking a {@link PropertyPath} as
* the relevant entity is that of the root of the path, and the path itself gets as dot separated String appended to the * argument, the relevant entity is that of the root of the path, and the path itself gets as dot separated String
* statement name. Each statement gets an instance of {@link MyBatisContext}, which at least has the entityType set. For * appended to the statement name. Each statement gets an instance of {@link MyBatisContext}, which at least has the
* methods taking a {@link PropertyPath} the entityTyoe if the context is set to the class of the leaf type. * 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 Jens Schauder
* @author Kazuki Shimizu * @author Kazuki Shimizu
@ -45,23 +47,29 @@ import org.springframework.data.mapping.PropertyPath;
public class MyBatisDataAccessStrategy implements DataAccessStrategy { public class MyBatisDataAccessStrategy implements DataAccessStrategy {
private final SqlSession sqlSession; 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 * Create a {@link DataAccessStrategy} that first checks for queries defined by MyBatis and if it doesn't find one
* used a {@link DefaultDataAccessStrategy} * uses a {@link DefaultDataAccessStrategy}
*
* @param context
* @param sqlSession
* @return
*/ */
public static DataAccessStrategy createCombinedAccessStrategy(JdbcMappingContext context, SqlSession sqlSession) { 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 // 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 // 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. // created. That is the purpose of the DelegatingAccessStrategy.
DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy(); DelegatingDataAccessStrategy delegatingDataAccessStrategy = new DelegatingDataAccessStrategy();
MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession); MyBatisDataAccessStrategy myBatisDataAccessStrategy = new MyBatisDataAccessStrategy(sqlSession);
myBatisDataAccessStrategy.setNamespaceStrategy(namespaceStrategy);
CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy( CascadingDataAccessStrategy cascadingDataAccessStrategy = new CascadingDataAccessStrategy(
asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy)); asList(myBatisDataAccessStrategy, delegatingDataAccessStrategy));
@ -92,11 +100,15 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
} }
/** /**
* Set a naming strategy for MyBatis objects. * Set a NamespaceStrategy to be used.
* @param namingStrategy Must be non {@literal null} *
* @param namespaceStrategy Must be non {@literal null}
*/ */
public void setNamingStrategy(MyBatisNamingStrategy namingStrategy) { public void setNamespaceStrategy(NamespaceStrategy namespaceStrategy) {
this.namingStrategy = namingStrategy;
Assert.notNull(namespaceStrategy, "The NamespaceStrategy must not be null");
this.namespaceStrategy = namespaceStrategy;
} }
@Override @Override
@ -168,7 +180,8 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
@Override @Override
public <T> Iterable<T> findAllByProperty(Object rootId, JdbcPersistentProperty property) { public <T> Iterable<T> 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())); new MyBatisContext(rootId, null, property.getType(), Collections.emptyMap()));
} }
@ -185,7 +198,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
} }
private String namespace(Class<?> domainType) { private String namespace(Class<?> domainType) {
return this.namingStrategy.getNamespace(domainType); return this.namespaceStrategy.getNamespace(domainType);
} }
private SqlSession sqlSession() { private SqlSession sqlSession() {

10
src/main/java/org/springframework/data/jdbc/mybatis/MyBatisNamingStrategy.java → src/main/java/org/springframework/data/jdbc/mybatis/NamespaceStrategy.java

@ -16,16 +16,20 @@
package org.springframework.data.jdbc.mybatis; 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 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.
* <p> * <p>
* By default, the namespace is based on the class of the entity plus the suffix "Mapper". * By default, the namespace is based on the class of the entity plus the suffix "Mapper".
*
* @param domainType Must be non {@literal null}. * @param domainType Must be non {@literal null}.
* @return a namespace that correspond domain type * @return a namespace that correspond domain type
*/ */

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

@ -15,12 +15,12 @@
*/ */
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 java.io.IOException;
import junit.framework.AssertionFailedError; import junit.framework.AssertionFailedError;
import java.io.IOException;
import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory; 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.data.repository.CrudRepository;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.test.context.ContextConfiguration; 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.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;
/** /**
* Tests the integration for customizing namespace with Mybatis. * Tests the integration for customizing the namespace with Mybatis.
* *
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Jens Schauder
*/ */
@ContextConfiguration @ContextConfiguration
@Transactional @Transactional
public class MyBatisCustomizingNamespaceHsqlIntegrationTests { 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 @org.springframework.context.annotation.Configuration
@Import(TestConfiguration.class) @Import(TestConfiguration.class)
@EnableJdbcRepositories(considerNestedRepositories = true) @EnableJdbcRepositories(considerNestedRepositories = true)
@ -85,37 +104,19 @@ public class MyBatisCustomizingNamespaceHsqlIntegrationTests {
@Bean @Bean
MyBatisDataAccessStrategy dataAccessStrategy(SqlSession sqlSession) { MyBatisDataAccessStrategy dataAccessStrategy(SqlSession sqlSession) {
MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession); MyBatisDataAccessStrategy strategy = new MyBatisDataAccessStrategy(sqlSession);
strategy.setNamingStrategy(new MyBatisNamingStrategy() {
strategy.setNamespaceStrategy(new NamespaceStrategy() {
@Override @Override
public String getNamespace(Class<?> domainType) { public String getNamespace(Class<?> domainType) {
return domainType.getPackage().getName() + ".mapper." + domainType.getSimpleName() + "Mapper"; return domainType.getPackage().getName() + ".mapper." + domainType.getSimpleName() + "Mapper";
} }
}); });
return strategy; return strategy;
} }
} }
@ClassRule public static final SpringClassRule classRule = new SpringClassRule(); interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
@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<DummyEntity, Long> {
}
} }

Loading…
Cancel
Save