From aa5de2fd65dd4a21c77718821803dbe11d6d1c35 Mon Sep 17 00:00:00 2001 From: Tatsuya Shimoda <tacoo@users.noreply.github.com> Date: Thu, 12 Dec 2019 17:02:19 +0900 Subject: [PATCH 1/5] Scan mappers from the package of the class that declares MapperScan annotation if basePackages attrubute is not present --- .../org/mybatis/spring/annotation/MapperScan.java | 5 +++++ .../spring/annotation/MapperScannerRegistrar.java | 14 +++++++++++--- .../mybatis/spring/annotation/MapperScanTest.java | 14 ++++++++++++++ .../mapper/AppConfigWithDefaultPackageScan.java | 10 ++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/mybatis/spring/mapper/AppConfigWithDefaultPackageScan.java diff --git a/src/main/java/org/mybatis/spring/annotation/MapperScan.java b/src/main/java/org/mybatis/spring/annotation/MapperScan.java index ee587e1775..8be5d010a6 100644 --- a/src/main/java/org/mybatis/spring/annotation/MapperScan.java +++ b/src/main/java/org/mybatis/spring/annotation/MapperScan.java @@ -31,6 +31,11 @@ /** * Use this annotation to register MyBatis mapper interfaces when using Java Config. It performs when same work as * {@link MapperScannerConfigurer} via {@link MapperScannerRegistrar}. + * + * <p>Either {@link #basePackageClasses} or {@link #basePackages} (or its alias + * {@link #value}) may be specified to define specific packages to scan. If specific + * packages are not defined, scanning will occur from the package of the + * class that declares this annotation. * * <p> * Configuration example: diff --git a/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java b/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java index af99f0406f..e77167de5f 100644 --- a/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java +++ b/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java @@ -70,11 +70,11 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B AnnotationAttributes mapperScanAttrs = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); if (mapperScanAttrs != null) { - registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0)); + registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0), getDefaultBasePackage(importingClassMetadata)); } } - void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { + void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName, String defaultBasePackage) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue("processPropertyPlaceHolders", true); @@ -119,6 +119,10 @@ void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegis basePackages.addAll(Arrays.stream(annoAttrs.getClassArray("basePackageClasses")).map(ClassUtils::getPackageName) .collect(Collectors.toList())); + if (basePackages.isEmpty()) { + basePackages.add(defaultBasePackage); + } + String lazyInitialization = annoAttrs.getString("lazyInitialization"); if (StringUtils.hasText(lazyInitialization)) { builder.addPropertyValue("lazyInitialization", lazyInitialization); @@ -134,6 +138,10 @@ private static String generateBaseBeanName(AnnotationMetadata importingClassMeta return importingClassMetadata.getClassName() + "#" + MapperScannerRegistrar.class.getSimpleName() + "#" + index; } + private static String getDefaultBasePackage(AnnotationMetadata importingClassMetadata) { + return ClassUtils.getPackageName(importingClassMetadata.getClassName()); + } + /** * A {@link MapperScannerRegistrar} for {@link MapperScans}. * @@ -150,7 +158,7 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B if (mapperScansAttrs != null) { AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value"); for (int i = 0; i < annotations.length; i++) { - registerBeanDefinitions(annotations[i], registry, generateBaseBeanName(importingClassMetadata, i)); + registerBeanDefinitions(annotations[i], registry, generateBaseBeanName(importingClassMetadata, i), getDefaultBasePackage(importingClassMetadata)); } } } diff --git a/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java b/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java index c46f04187b..6ef2286712 100644 --- a/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java +++ b/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java @@ -28,6 +28,7 @@ import org.mybatis.spring.SqlSessionTemplate; import org.mybatis.spring.annotation.mapper.ds1.Ds1Mapper; import org.mybatis.spring.mapper.AnnotatedMapper; +import org.mybatis.spring.mapper.AppConfigWithDefaultPackageScan; import org.mybatis.spring.mapper.MapperInterface; import org.mybatis.spring.mapper.MapperSubinterface; import org.mybatis.spring.mapper.child.MapperChildInterface; @@ -90,6 +91,19 @@ void assertNoMapperClass() { } } + @Test + void testDefaultMapperScan() { + applicationContext.register(AppConfigWithDefaultPackageScan.class); + + startContext(); + + // all interfaces with methods should be loaded + applicationContext.getBean("mapperInterface"); + applicationContext.getBean("mapperSubinterface"); + applicationContext.getBean("mapperChildInterface"); + applicationContext.getBean("annotatedMapper"); + } + @Test void testInterfaceScan() { applicationContext.register(AppConfigWithPackageScan.class); diff --git a/src/test/java/org/mybatis/spring/mapper/AppConfigWithDefaultPackageScan.java b/src/test/java/org/mybatis/spring/mapper/AppConfigWithDefaultPackageScan.java new file mode 100644 index 0000000000..dc3e95ec1d --- /dev/null +++ b/src/test/java/org/mybatis/spring/mapper/AppConfigWithDefaultPackageScan.java @@ -0,0 +1,10 @@ +package org.mybatis.spring.mapper; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan +public class AppConfigWithDefaultPackageScan { + +} From 8623026b5e024f4311eeb3f58a90230003f47674 Mon Sep 17 00:00:00 2001 From: shimoda <tatsuya.fuga@gmail.com> Date: Fri, 13 Dec 2019 11:51:47 +0900 Subject: [PATCH 2/5] added more tests and fixed javadoc --- .../mybatis/spring/annotation/MapperScan.java | 6 ++-- .../spring/annotation/MapperScanTest.java | 28 +++++++++++++++++++ ...pConfigWithDefaultMapperScanAndRepeat.java | 10 +++++++ .../ds1/AppConfigWithDefaultMapperScans.java | 13 +++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScanAndRepeat.java create mode 100644 src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScans.java diff --git a/src/main/java/org/mybatis/spring/annotation/MapperScan.java b/src/main/java/org/mybatis/spring/annotation/MapperScan.java index 8be5d010a6..159a5fa89c 100644 --- a/src/main/java/org/mybatis/spring/annotation/MapperScan.java +++ b/src/main/java/org/mybatis/spring/annotation/MapperScan.java @@ -33,9 +33,9 @@ * {@link MapperScannerConfigurer} via {@link MapperScannerRegistrar}. * * <p>Either {@link #basePackageClasses} or {@link #basePackages} (or its alias - * {@link #value}) may be specified to define specific packages to scan. If specific - * packages are not defined, scanning will occur from the package of the - * class that declares this annotation. + * {@link #value}) may be specified to define specific packages to scan. + * Since 2.0.4, If specific packages are not defined, scanning will occur from + * the package of the class that declares this annotation. * * <p> * Configuration example: diff --git a/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java b/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java index 6ef2286712..0b54054a0c 100644 --- a/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java +++ b/src/test/java/org/mybatis/spring/annotation/MapperScanTest.java @@ -26,6 +26,8 @@ import org.junit.jupiter.api.Test; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.SqlSessionTemplate; +import org.mybatis.spring.annotation.mapper.ds1.AppConfigWithDefaultMapperScanAndRepeat; +import org.mybatis.spring.annotation.mapper.ds1.AppConfigWithDefaultMapperScans; import org.mybatis.spring.annotation.mapper.ds1.Ds1Mapper; import org.mybatis.spring.mapper.AnnotatedMapper; import org.mybatis.spring.mapper.AppConfigWithDefaultPackageScan; @@ -289,6 +291,32 @@ void testScanWithMapperScans() { applicationContext.getBean("ds2Mapper"); } + @Test + void testScanWithDefaultMapperScanAndRepeat() { + applicationContext.register(AppConfigWithDefaultMapperScanAndRepeat.class); + + startContext(); + + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(2, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + + applicationContext.getBean("ds1Mapper"); + applicationContext.getBean("ds2Mapper"); + } + + @Test + void testScanWithDefaultMapperScans() { + applicationContext.register(AppConfigWithDefaultMapperScans.class); + + startContext(); + + SqlSessionFactory sqlSessionFactory = applicationContext.getBean(SqlSessionFactory.class); + assertEquals(2, sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers().size()); + + applicationContext.getBean("ds1Mapper"); + applicationContext.getBean("ds2Mapper"); + } + @Test void testLazyScanWithPropertySourcesPlaceholderConfigurer() { applicationContext.register(LazyConfigWithPropertySourcesPlaceholderConfigurer.class); diff --git a/src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScanAndRepeat.java b/src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScanAndRepeat.java new file mode 100644 index 0000000000..a6edbcad18 --- /dev/null +++ b/src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScanAndRepeat.java @@ -0,0 +1,10 @@ +package org.mybatis.spring.annotation.mapper.ds1; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScan +@MapperScan("org.mybatis.spring.annotation.mapper.ds2") +public class AppConfigWithDefaultMapperScanAndRepeat { +} diff --git a/src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScans.java b/src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScans.java new file mode 100644 index 0000000000..af3e1364f7 --- /dev/null +++ b/src/test/java/org/mybatis/spring/annotation/mapper/ds1/AppConfigWithDefaultMapperScans.java @@ -0,0 +1,13 @@ +package org.mybatis.spring.annotation.mapper.ds1; + +import org.mybatis.spring.annotation.MapperScan; +import org.mybatis.spring.annotation.MapperScans; +import org.springframework.context.annotation.Configuration; + +@Configuration +@MapperScans({ + @MapperScan, + @MapperScan("org.mybatis.spring.annotation.mapper.ds2") +}) +public class AppConfigWithDefaultMapperScans { +} From 33e568af40d68d5cff9ba86fa283514df8e3f4e3 Mon Sep 17 00:00:00 2001 From: shimoda <tatsuya.fuga@gmail.com> Date: Fri, 13 Dec 2019 12:18:05 +0900 Subject: [PATCH 3/5] added a note in the document --- src/site/xdoc/mappers.xml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/site/xdoc/mappers.xml b/src/site/xdoc/mappers.xml index 304b6fecab..62fe64b118 100644 --- a/src/site/xdoc/mappers.xml +++ b/src/site/xdoc/mappers.xml @@ -247,7 +247,11 @@ public class AppConfig { You can also provide an specific <code>SqlSessionFactory</code> or <code>SqlSessionTemplate</code> by using its properties <code>sqlSessionFactory</code> and <code>sqlSessionTemplate</code>. </p> - + + <p> + <span class="label important">NOTE</span> Since 2.0.4, If <code>basePackageClasses</code> or <code>basePackages</code> are not defined, scanning will occur from the package of the class that declares this annotation. + </p> + <h4>MapperScannerConfigurer</h4> <p> From be079d6a0ab115883d604d15a7afdf71ca645f13 Mon Sep 17 00:00:00 2001 From: Tatsuya Shimoda <tacoo@users.noreply.github.com> Date: Sat, 14 Dec 2019 03:17:28 +0900 Subject: [PATCH 4/5] added AnnotationAttributes as a param --- .../mybatis/spring/annotation/MapperScannerRegistrar.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java b/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java index e77167de5f..e9b1546365 100644 --- a/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java +++ b/src/main/java/org/mybatis/spring/annotation/MapperScannerRegistrar.java @@ -70,11 +70,11 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B AnnotationAttributes mapperScanAttrs = AnnotationAttributes .fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName())); if (mapperScanAttrs != null) { - registerBeanDefinitions(mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0), getDefaultBasePackage(importingClassMetadata)); + registerBeanDefinitions(importingClassMetadata, mapperScanAttrs, registry, generateBaseBeanName(importingClassMetadata, 0)); } } - void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName, String defaultBasePackage) { + void registerBeanDefinitions(AnnotationMetadata annoMeta, AnnotationAttributes annoAttrs, BeanDefinitionRegistry registry, String beanName) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MapperScannerConfigurer.class); builder.addPropertyValue("processPropertyPlaceHolders", true); @@ -120,7 +120,7 @@ void registerBeanDefinitions(AnnotationAttributes annoAttrs, BeanDefinitionRegis .collect(Collectors.toList())); if (basePackages.isEmpty()) { - basePackages.add(defaultBasePackage); + basePackages.add(getDefaultBasePackage(annoMeta)); } String lazyInitialization = annoAttrs.getString("lazyInitialization"); @@ -158,7 +158,7 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B if (mapperScansAttrs != null) { AnnotationAttributes[] annotations = mapperScansAttrs.getAnnotationArray("value"); for (int i = 0; i < annotations.length; i++) { - registerBeanDefinitions(annotations[i], registry, generateBaseBeanName(importingClassMetadata, i), getDefaultBasePackage(importingClassMetadata)); + registerBeanDefinitions(importingClassMetadata, annotations[i], registry, generateBaseBeanName(importingClassMetadata, i)); } } } From a9fce71a747ff8773d2aa452b6ba8912098f3642 Mon Sep 17 00:00:00 2001 From: Tatsuya Shimoda <tacoo@users.noreply.github.com> Date: Sat, 14 Dec 2019 03:39:11 +0900 Subject: [PATCH 5/5] added i18n docs --- src/site/es/xdoc/mappers.xml | 6 +++++- src/site/ja/xdoc/mappers.xml | 6 +++++- src/site/ko/xdoc/mappers.xml | 6 +++++- src/site/zh/xdoc/mappers.xml | 4 ++++ 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/site/es/xdoc/mappers.xml b/src/site/es/xdoc/mappers.xml index 0baebebce8..de81624425 100644 --- a/src/site/es/xdoc/mappers.xml +++ b/src/site/es/xdoc/mappers.xml @@ -234,7 +234,11 @@ public class AppConfig { Tambien puedes indicar una <code>SqlSessionFactory</code> o un <code>SqlSessionTemplate</code> específicos mediante las propiedades <code>sqlSessionFactory</code> y <code>sqlSessionTemplate</code>. </p> - + + <p> + <span class="label important">NOTE</span> Since 2.0.4, If <code>basePackageClasses</code> or <code>basePackages</code> are not defined, scanning will occur from the package of the class that declares this annotation. + </p> + <h4>MapperScannerConfigurer</h4> <p> diff --git a/src/site/ja/xdoc/mappers.xml b/src/site/ja/xdoc/mappers.xml index 1890b478df..d477515352 100644 --- a/src/site/ja/xdoc/mappers.xml +++ b/src/site/ja/xdoc/mappers.xml @@ -210,7 +210,11 @@ public class AppConfig { このアノテーションは前章で説明した <code><mybatis:scan/></code> と全く同じ要領で Mapper の検出を行います。 引数 <code>markerInterface</code>, <code>annotationClass</code> を使えば検出対象のマーカーインターフェイスとアノテーションを指定することもできますし、<code>sqlSessionFactory</code>, <code>sqlSessionTemplate</code> で <code>SqlSessionFactory</code> や <code>SqlSessionTemplate</code> を指定することができます。 </p> - + + <p> + <span class="label important">NOTE</span> 2.0.4以降では、 <code>basePackageClasses</code> もしくは <code>basePackages</code> が指定されていない場合、このアノテーションが定義されているクラスのパッケージを基準にスキャンします。 + </p> + <h4>MapperScannerConfigurer</h4> <p> diff --git a/src/site/ko/xdoc/mappers.xml b/src/site/ko/xdoc/mappers.xml index 3a2acb6b30..08abb2e8de 100644 --- a/src/site/ko/xdoc/mappers.xml +++ b/src/site/ko/xdoc/mappers.xml @@ -191,7 +191,11 @@ public class AppConfig { <code>markerInterface</code> 와 <code>annotationClass</code> 프로퍼티를 사용해서 마커 인터페이스와 애노테이션 클래스를 명시하게 한다. <code>sqlSessionFactory</code> 와 <code>sqlSessionTemplate</code> 프로퍼티를 사용해서 <code>SqlSessionFactory</code> 나 <code>SqlSessionTemplate</code>을 제공할 수도 있다. </p> - + + <p> + <span class="label important">NOTE</span> Since 2.0.4, If <code>basePackageClasses</code> or <code>basePackages</code> are not defined, scanning will occur from the package of the class that declares this annotation. + </p> + <h4>MapperScannerConfigurer</h4> <p><code>MapperScannerConfigurer</code>는 평범한 빈처럼 XML애플리케이션 컨텍스트에 포함된 <code>BeanDefinitionRegistryPostProcessor</code> 이다. diff --git a/src/site/zh/xdoc/mappers.xml b/src/site/zh/xdoc/mappers.xml index 34320c51b3..a426f640ce 100644 --- a/src/site/zh/xdoc/mappers.xml +++ b/src/site/zh/xdoc/mappers.xml @@ -195,6 +195,10 @@ public class AppConfig { 这个注解具有与之前见过的 <code><mybatis:scan/></code> 元素一样的工作方式。它也可以通过 <code>markerInterface</code> 和 <code>annotationClass</code> 属性设置标记接口或注解类。通过配置 <code>sqlSessionFactory</code> 和 <code>sqlSessionTemplate</code> 属性,你还能指定一个 <code>SqlSessionFactory</code> 或 <code>SqlSessionTemplate</code>。 </p> + <p> + <span class="label important">NOTE</span> Since 2.0.4, If <code>basePackageClasses</code> or <code>basePackages</code> are not defined, scanning will occur from the package of the class that declares this annotation. + </p> + <h4>MapperScannerConfigurer</h4> <p>