DATAJDBC-136 - Fix ClassNotFoundException when MyBatis is not on the classpath.

This commit is contained in:
Jens Schauder
2017-10-25 14:57:55 +02:00
committed by Greg Turnquist
parent 1291b5d33c
commit 2fbb3b00c7
2 changed files with 38 additions and 3 deletions

View File

@@ -118,12 +118,22 @@ public class JdbcRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extend
private Optional<DataAccessStrategy> createMyBatisDataAccessStrategy() {
if (!ClassUtils.isPresent("org.apache.ibatis.session.SqlSessionFactory", this.getClass().getClassLoader())) {
String myBatisSqlSessionFactoryClassName = "org.apache.ibatis.session.SqlSessionFactory";
ClassLoader classLoader = this.getClass().getClassLoader();
if (!ClassUtils.isPresent(myBatisSqlSessionFactoryClassName, classLoader)) {
return Optional.empty();
}
return getBean(SqlSessionFactory.class, SQL_SESSION_FACTORY_BEAN_NAME)
.map(ssf -> new MyBatisDataAccessStrategy(ssf));
try {
return getBean(classLoader.loadClass(myBatisSqlSessionFactoryClassName), SQL_SESSION_FACTORY_BEAN_NAME)
// note that the cast to SqlSessionFactory happens in a lambda, which is basically a separate class
// thus it won't get loaded if this code path doesn't get executed.
.map(ssf -> new MyBatisDataAccessStrategy((SqlSessionFactory) ssf));
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Detected MyBatis on classpath but failed to load the class " + myBatisSqlSessionFactoryClassName);
}
}
private Optional<DataAccessStrategy> createDefaultAccessStrategy(JdbcMappingContext context,

View File

@@ -25,9 +25,11 @@ import org.springframework.data.jdbc.core.DelegatingDataAccessStrategy;
import org.springframework.data.jdbc.mybatis.MyBatisDataAccessStrategy;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.instrument.classloading.ShadowingClassLoader;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
import org.springframework.util.ReflectionUtils;
/**
* Tests the dependency injection for {@link JdbcRepositoryFactoryBean}.
@@ -211,6 +213,29 @@ public class JdbcRepositoryFactoryBeanUnitTests {
assertThat(findDataAccessStrategy(factory, MyBatisDataAccessStrategy.class)).isNotNull();
}
@Test // DATAJDBC-136
public void canBeLoadedWithoutMyBatis() throws Exception {
String sqlSessionFactoryClassName = SqlSessionFactory.class.getName();
ShadowingClassLoader classLoader = new ShadowingClassLoader(this.getClass().getClassLoader()) {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if (name.equals(sqlSessionFactoryClassName)) {
throw new ClassNotFoundException("%s is configured not to get loaded by this classloader");
}
return super.loadClass(name);
}
};
Class<?> loadedClass = classLoader.loadClass(JdbcRepositoryFactoryBean.class.getName());
assertThat(loadedClass).isNotNull();
ReflectionUtils.getAllDeclaredMethods(loadedClass);
}
private Condition<? super RepositoryFactorySupport> using(NamedParameterJdbcOperations expectedOperations) {
Predicate<RepositoryFactorySupport> predicate = r -> extractNamedParameterJdbcOperations(r) == expectedOperations;