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>&lt;mybatis:scan/&gt;</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>&lt;mybatis:scan/&gt;</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>