Skip to content

Commit

Permalink
Allow to specify a wildcard at typeAliasesPackage and typeHandlersPac…
Browse files Browse the repository at this point in the history
…kage

Related with gh-175
  • Loading branch information
kazuki43zoo committed Apr 4, 2019
1 parent 457c685 commit 4d17ab1
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 26 deletions.
79 changes: 56 additions & 23 deletions src/main/java/org/mybatis/spring/SqlSessionFactoryBean.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,21 @@
*/
package org.mybatis.spring;

import static org.springframework.util.Assert.notNull;
import static org.springframework.util.Assert.state;
import static org.springframework.util.ObjectUtils.isEmpty;
import static org.springframework.util.StringUtils.hasLength;
import static org.springframework.util.StringUtils.tokenizeToStringArray;

import javax.sql.DataSource;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Stream;

import javax.sql.DataSource;

import org.apache.ibatis.builder.xml.XMLConfigBuilder;
import org.apache.ibatis.builder.xml.XMLMapperBuilder;
import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.io.VFS;
import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.Environment;
Expand All @@ -55,7 +52,19 @@
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.NestedIOException;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.util.ClassUtils;

import static org.springframework.util.Assert.notNull;
import static org.springframework.util.Assert.state;
import static org.springframework.util.ObjectUtils.isEmpty;
import static org.springframework.util.StringUtils.hasLength;
import static org.springframework.util.StringUtils.tokenizeToStringArray;

/**
* {@code FactoryBean} that creates an MyBatis {@code SqlSessionFactory}.
Expand All @@ -79,6 +88,9 @@ public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, In

private static final Logger LOGGER = LoggerFactory.getLogger(SqlSessionFactoryBean.class);

private static final ResourcePatternResolver RESOURCE_PATTERN_RESOLVER = new PathMatchingResourcePatternResolver();
private static final MetadataReaderFactory METADATA_READER_FACTORY = new CachingMetadataReaderFactory();

private Resource configLocation;

private Configuration configuration;
Expand Down Expand Up @@ -211,6 +223,8 @@ public void setPlugins(Interceptor[] plugins) {
/**
* Packages to search for type aliases.
*
* <p>Since 2.0.1, allow to specify a wildcard such as <code>com.example.*.model</code>.
*
* @since 1.0.1
*
* @param typeAliasesPackage package to scan for domain objects
Expand All @@ -236,6 +250,8 @@ public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
/**
* Packages to search for type handlers.
*
* <p>Since 2.0.1, allow to specify a wildcard such as <code>com.example.*.typehandler</code>.
* @since 1.0.1
*
* @param typeHandlersPackage package to scan for type handlers
Expand Down Expand Up @@ -416,9 +432,9 @@ public void afterPropertiesSet() throws Exception {
* Since 1.3.0, it can be specified a {@link Configuration} instance directly(without config file).
*
* @return SqlSessionFactory
* @throws IOException if loading the config file failed
* @throws Exception if configuration is failed
*/
protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
protected SqlSessionFactory buildSqlSessionFactory() throws Exception {

final Configuration targetConfiguration;

Expand All @@ -444,13 +460,8 @@ protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
Optional.ofNullable(this.vfs).ifPresent(targetConfiguration::setVfsImpl);

if (hasLength(this.typeAliasesPackage)) {
String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Stream.of(typeAliasPackageArray).forEach(packageToScan -> {
targetConfiguration.getTypeAliasRegistry().registerAliases(packageToScan,
typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
LOGGER.debug(() -> "Scanned package: '" + packageToScan + "' for aliases");
});
scanClasses(this.typeAliasesPackage, this.typeAliasesSuperType)
.forEach(targetConfiguration.getTypeAliasRegistry()::registerAlias);
}

if (!isEmpty(this.typeAliases)) {
Expand All @@ -468,12 +479,11 @@ protected SqlSessionFactory buildSqlSessionFactory() throws IOException {
}

if (hasLength(this.typeHandlersPackage)) {
String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Stream.of(typeHandlersPackageArray).forEach(packageToScan -> {
targetConfiguration.getTypeHandlerRegistry().register(packageToScan);
LOGGER.debug(() -> "Scanned package: '" + packageToScan + "' for type handlers");
});
scanClasses(this.typeHandlersPackage, TypeHandler.class).stream()
.filter(clazz -> !clazz.isInterface())
.filter(clazz -> !Modifier.isAbstract(clazz.getModifiers()))
.filter(clazz -> ClassUtils.getConstructorIfAvailable(clazz) != null)
.forEach(targetConfiguration.getTypeHandlerRegistry()::register);
}

if (!isEmpty(this.typeHandlers)) {
Expand Down Expand Up @@ -571,4 +581,27 @@ public void onApplicationEvent(ApplicationEvent event) {
}
}

private Set<Class<?>> scanClasses(String packagePatterns, Class<?> assignableType)
throws IOException {
Set<Class<?>> classes = new HashSet<>();
String[] packagePatternArray = tokenizeToStringArray(packagePatterns,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
for (String packagePattern : packagePatternArray) {
Resource[] resources = RESOURCE_PATTERN_RESOLVER.getResources(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(packagePattern) + "/**/*.class");
for (Resource resource : resources) {
try {
ClassMetadata classMetadata = METADATA_READER_FACTORY.getMetadataReader(resource).getClassMetadata();
Class<?> clazz = Resources.classForName(classMetadata.getClassName());
if (assignableType == null || assignableType.isAssignableFrom(clazz)) {
classes.add(clazz);
}
} catch (Throwable e) {
LOGGER.warn(() -> "Cannot load the '" + resource + "'. Cause by " + e.toString());
}
}
}
return classes;
}

}
28 changes: 25 additions & 3 deletions src/test/java/org/mybatis/spring/SqlSessionFactoryBeanTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ void testAddATypeAlias() throws Exception {
@Test
void testSearchATypeAliasPackage() throws Exception {
setupFactoryBean();
factoryBean.setTypeAliasesPackage("org/mybatis/spring/type");
factoryBean.setTypeAliasesPackage("org.mybatis.spring.type");

TypeAliasRegistry typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
typeAliasRegistry.resolveAlias("testAlias");
Expand All @@ -354,7 +354,7 @@ void testSearchATypeAliasPackage() throws Exception {
void testSearchATypeAliasPackageWithSuperType() throws Exception {
setupFactoryBean();
factoryBean.setTypeAliasesSuperType(SuperType.class);
factoryBean.setTypeAliasesPackage("org/mybatis/spring/type");
factoryBean.setTypeAliasesPackage("org.mybatis.*.type");

TypeAliasRegistry typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
typeAliasRegistry.resolveAlias("testAlias2");
Expand All @@ -364,10 +364,32 @@ void testSearchATypeAliasPackageWithSuperType() throws Exception {
assertThrows(TypeException.class, () -> typeAliasRegistry.resolveAlias("dummyTypeHandler"));
}

@Test
void testSearchATypeAliasPackageWithSamePackage() throws Exception {
setupFactoryBean();
factoryBean.setTypeAliasesPackage("org.mybatis.spring.type, org.*.spring.type");

TypeAliasRegistry typeAliasRegistry = factoryBean.getObject().getConfiguration().getTypeAliasRegistry();
typeAliasRegistry.resolveAlias("testAlias");
typeAliasRegistry.resolveAlias("testAlias2");
typeAliasRegistry.resolveAlias("dummyTypeHandler");
typeAliasRegistry.resolveAlias("superType");
}

@Test
void testSearchATypeHandlerPackage() throws Exception {
setupFactoryBean();
factoryBean.setTypeHandlersPackage("org/mybatis/spring/type");
factoryBean.setTypeHandlersPackage("org.**.type");

TypeHandlerRegistry typeHandlerRegistry = factoryBean.getObject().getConfiguration().getTypeHandlerRegistry();
assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
assertThat(typeHandlerRegistry.hasTypeHandler(BigDecimal.class)).isTrue();
}

@Test
void testSearchATypeHandlerPackageWithSamePackage() throws Exception {
setupFactoryBean();
factoryBean.setTypeHandlersPackage("org.mybatis.spring.type, org.mybatis.*.type");

TypeHandlerRegistry typeHandlerRegistry = factoryBean.getObject().getConfiguration().getTypeHandlerRegistry();
assertThat(typeHandlerRegistry.hasTypeHandler(BigInteger.class)).isTrue();
Expand Down

0 comments on commit 4d17ab1

Please sign in to comment.