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; @@ -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; @@ -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 { @@ -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 { @@ -168,7 +180,8 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy {
@Override
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()));
}
@ -185,7 +198,7 @@ public class MyBatisDataAccessStrategy implements DataAccessStrategy { @@ -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() {

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 @@ @@ -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.
* <p>
* 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
*/

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

@ -15,12 +15,12 @@ @@ -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; @@ -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 { @@ -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<DummyEntity, Long> {
}
interface DummyEntityRepository extends CrudRepository<DummyEntity, Long> {}
}

Loading…
Cancel
Save