Skip to content

Commit

Permalink
Change to support spring-native
Browse files Browse the repository at this point in the history
* Set sqlSessionTemplateBeanName or sqlSessionFactoryBeanName at scanning mapper
* Add new configuration property for configure inject sql session on mapper scan
* Update mybatis-spring 2.0.7-SNAPSHOT

See gh-617
  • Loading branch information
kazuki43zoo committed Jan 4, 2022
1 parent 73b74dc commit ba522d5
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2021 the original author or authors.
* Copyright 2015-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@

import java.beans.PropertyDescriptor;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -42,7 +43,9 @@
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
Expand All @@ -53,9 +56,11 @@
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
Expand Down Expand Up @@ -208,9 +213,11 @@ public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory
* {@link org.mybatis.spring.annotation.MapperScan} but this will get typed mappers working correctly, out-of-the-box,
* similar to using Spring Data JPA repositories.
*/
public static class AutoConfiguredMapperScannerRegistrar implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
public static class AutoConfiguredMapperScannerRegistrar
implements BeanFactoryAware, EnvironmentAware, ImportBeanDefinitionRegistrar {

private BeanFactory beanFactory;
private Environment environment;

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Expand Down Expand Up @@ -242,6 +249,25 @@ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, B
// Need to mybatis-spring 2.0.6+
builder.addPropertyValue("defaultScope", "${mybatis.mapper-default-scope:}");
}

// for spring-native
boolean injectSqlSession = environment.getProperty("mybatis.inject-sql-session-on-mapper-scan", Boolean.class,
Boolean.TRUE);
if (injectSqlSession && this.beanFactory instanceof ListableBeanFactory) {
ListableBeanFactory listableBeanFactory = (ListableBeanFactory) this.beanFactory;
Optional<String> sqlSessionTemplateBeanName = Optional
.ofNullable(getBeanNameForType(SqlSessionTemplate.class, listableBeanFactory));
Optional<String> sqlSessionFactoryBeanName = Optional
.ofNullable(getBeanNameForType(SqlSessionFactory.class, listableBeanFactory));
if (sqlSessionTemplateBeanName.isPresent() || !sqlSessionFactoryBeanName.isPresent()) {
builder.addPropertyValue("sqlSessionTemplateBeanName",
sqlSessionTemplateBeanName.orElse("sqlSessionTemplate"));
} else {
builder.addPropertyValue("sqlSessionFactoryBeanName", sqlSessionFactoryBeanName.get());
}
}
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

registry.registerBeanDefinition(MapperScannerConfigurer.class.getName(), builder.getBeanDefinition());
}

Expand All @@ -250,6 +276,16 @@ public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}

@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}

private String getBeanNameForType(Class<?> type, ListableBeanFactory factory) {
String[] beanNames = factory.getBeanNamesForType(type);
return beanNames.length > 0 ? beanNames[0] : null;
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
"description": "A default scope for mapper bean that scanned by auto-configure.",
"type": "java.lang.String"
},
{
"defaultValue": true,
"name": "mybatis.inject-sql-session-on-mapper-scan",
"description": "Set whether inject a SqlSessionTemplate or SqlSessionFactory bean (If you want to back to the behavior of 2.2.1 or before, specify false). If you use together with spring-native, should be set true.",
"type": "java.lang.Boolean"
},
{
"name": "mybatis.scripting-language-driver.velocity.userdirective",
"deprecation": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Available properties are:
| `configuration-properties` | Externalized properties for MyBatis configuration. Specified properties can be used as placeholder on MyBatis config file and Mapper file. For detail see the [MyBatis reference page](http://www.mybatis.org/mybatis-3/configuration.html#properties). |
| `lazy-initialization` | Whether enable lazy initialization of mapper bean. Set `true` to enable lazy initialization. This feature requires to use together with mybatis-spring 2.0.2+. |
| `mapper-default-scope` | Default scope for mapper bean that scanned by auto-configure. This feature requires to use together with mybatis-spring 2.0.6+. |
| `mybatis.inject-sql-session-on-mapper-scan` | Set whether inject a `SqlSessionTemplate` or `SqlSessionFactory` bean (If you want to back to the behavior of 2.2.1 or before, specify `false`). If you use together with spring-native, should be set `true`(default). |
| `configuration.*` | Property keys for `Configuration` bean provided by MyBatis Core. About available nested properties see the [MyBatis reference page](http://www.mybatis.org/mybatis-3/configuration.html#settings). <span class="label important">NOTE</span>: This property cannot be used at the same time with the `config-location`. |
| `scripting-language-driver.thymeleaf.*` | Property keys for `ThymeleafLanguageDriverConfig` bean provided by MyBatis Thymeleaf. About available nested properties see the [MyBatis Thymeleaf reference page](http://www.mybatis.org/thymeleaf-scripting/user-guide.html#_configuration_properties). |
| `scripting-language-driver.freemarker.*` | Properties keys for `FreeMarkerLanguageDriverConfig` bean provided by MyBatis FreeMarker. About available nested properties see the [MyBatis FreeMarker reference page](http://www.mybatis.org/freemarker-scripting/#Configuration). This feature requires to use together with mybatis-freemarker 1.2.0+. |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2021 the original author or authors.
* Copyright 2015-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -45,7 +45,7 @@ void testProperties() throws IOException {

List<Map<String, Object>> properties = documentContext.read("$.properties");

assertAll(() -> assertThat(properties.size()).isEqualTo(5), () -> {
assertAll(() -> assertThat(properties.size()).isEqualTo(6), () -> {
// assert for mybatis.configuration.default-scripting-language
Map<String, Object> element = properties.get(0);
assertThat(element.get("sourceType")).isEqualTo("org.apache.ibatis.session.Configuration");
Expand Down Expand Up @@ -78,8 +78,14 @@ void testProperties() throws IOException {
assertThat(element.get("name")).isEqualTo("mybatis.mapper-default-scope");
assertThat(element.get("type")).isEqualTo("java.lang.String");
}, () -> {
// assert for mybatis.scripting-language-driver.velocity.userdirective
// assert for mybatis.inject-sql-session-on-mapper-scan
Map<String, Object> element = properties.get(4);
assertThat(element.get("defaultValue")).isEqualTo(true);
assertThat(element.get("name")).isEqualTo("mybatis.inject-sql-session-on-mapper-scan");
assertThat(element.get("type")).isEqualTo("java.lang.Boolean");
}, () -> {
// assert for mybatis.scripting-language-driver.velocity.userdirective
Map<String, Object> element = properties.get(5);
assertThat(element.get("name")).isEqualTo("mybatis.scripting-language-driver.velocity.userdirective");
@SuppressWarnings("unchecked")
Map<String, Object> deprecation = (Map<String, Object>) element.get("deprecation");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2021 the original author or authors.
* Copyright 2015-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -75,6 +75,7 @@
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
Expand Down Expand Up @@ -183,6 +184,46 @@ void testScanWithLazy() {
assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
}

@Test
void testAutoScanWithDefault() {
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
MybatisAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
SqlSessionFactory sqlSessionFactory = this.context.getBean(SqlSessionFactory.class);
assertThat(this.context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
assertThat(this.context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
assertThat(this.context.getBeanNamesForType(CityMapper.class)).hasSize(1);
assertThat(this.context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
assertThat(this.context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase()).isFalse();
this.context.getBean(CityMapper.class);
assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
assertThat(((RuntimeBeanReference) this.context.getBeanDefinition("cityMapper").getPropertyValues()
.getPropertyValue("sqlSessionTemplate").getValue()).getBeanName()).isEqualTo("sqlSessionTemplate");
assertThat(
this.context.getBeanDefinition(this.context.getBeanNamesForType(MapperScannerConfigurer.class)[0]).getRole())
.isEqualTo(BeanDefinition.ROLE_INFRASTRUCTURE);
}

@Test
void testAutoScanWithInjectSqlSessionOnMapperScanIsFalse() {
TestPropertyValues.of("mybatis.inject-sql-session-on-mapper-scan:false").applyTo(this.context);
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
MybatisAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
SqlSessionFactory sqlSessionFactory = this.context.getBean(SqlSessionFactory.class);
assertThat(this.context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
assertThat(this.context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
assertThat(this.context.getBeanNamesForType(CityMapper.class)).hasSize(1);
assertThat(this.context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.SIMPLE);
assertThat(this.context.getBean(SqlSessionFactory.class).getConfiguration().isMapUnderscoreToCamelCase()).isFalse();
this.context.getBean(CityMapper.class);
assertThat(sqlSessionFactory.getConfiguration().getMapperRegistry().getMappers()).hasSize(1);
assertThat(this.context.getBeanDefinition("cityMapper").getPropertyValues().getPropertyValue("sqlSessionTemplate"))
.isNull();
assertThat(this.context.getBeanDefinition("cityMapper").getPropertyValues().getPropertyValue("sqlSessionFactory"))
.isNull();
}

@Test
void testAutoScanWithLazy() {
TestPropertyValues.of("mybatis.lazy-initialization:true").applyTo(this.context);
Expand Down Expand Up @@ -601,12 +642,15 @@ void testWithConfigurationVariablesAndPropertiesSameKey() {

@Test
void testCustomSqlSessionFactory() {
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisAutoConfiguration.class,
CustomSqlSessionFactoryConfiguration.class);
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
CustomSqlSessionFactoryConfiguration.class, MybatisAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBeanNamesForType(SqlSessionFactory.class)).hasSize(1);
assertThat(this.context.getBean(SqlSessionFactory.class).getConfiguration().getVariables().getProperty("key"))
.isEqualTo("value");
assertThat(this.context.getBeanNamesForType(CityMapper.class)).hasSize(1);
assertThat(((RuntimeBeanReference) this.context.getBeanDefinition("cityMapper").getPropertyValues()
.getPropertyValue("sqlSessionFactory").getValue()).getBeanName()).isEqualTo("customSqlSessionFactory");
}

@Test
Expand All @@ -620,11 +664,14 @@ void testMySqlSessionFactory() {

@Test
void testCustomSqlSessionTemplate() {
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisAutoConfiguration.class,
CustomSqlSessionTemplateConfiguration.class);
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
CustomSqlSessionTemplateConfiguration.class, MybatisAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
assertThat(this.context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
assertThat(this.context.getBeanNamesForType(CityMapper.class)).hasSize(1);
assertThat(((RuntimeBeanReference) this.context.getBeanDefinition("cityMapper").getPropertyValues()
.getPropertyValue("sqlSessionTemplate").getValue()).getBeanName()).isEqualTo("customSqlSessionTemplate");
}

@Test
Expand All @@ -636,6 +683,19 @@ void testMySqlSessionTemplate() {
assertThat(this.context.getBean(SqlSessionTemplate.class)).isInstanceOf(MySqlSessionTemplate.class);
}

@Test
void testCustomSqlSessionTemplateAndSqlSessionFactory() {
this.context.register(EmbeddedDataSourceConfiguration.class, MybatisBootMapperScanAutoConfiguration.class,
CustomSqlSessionFactoryConfiguration.class, CustomSqlSessionTemplateConfiguration.class,
MybatisAutoConfiguration.class);
this.context.refresh();
assertThat(this.context.getBeanNamesForType(SqlSessionTemplate.class)).hasSize(1);
assertThat(this.context.getBean(SqlSessionTemplate.class).getExecutorType()).isEqualTo(ExecutorType.BATCH);
assertThat(this.context.getBeanNamesForType(CityMapper.class)).hasSize(1);
assertThat(((RuntimeBeanReference) this.context.getBeanDefinition("cityMapper").getPropertyValues()
.getPropertyValue("sqlSessionTemplate").getValue()).getBeanName()).isEqualTo("customSqlSessionTemplate");
}

@Test
void testTypeAliasesSuperTypeIsSpecify() {
TestPropertyValues
Expand Down Expand Up @@ -965,7 +1025,7 @@ public VendorDatabaseIdProvider vendorDatabaseIdProvider(Properties vendorProper
@Configuration
static class CustomSqlSessionFactoryConfiguration {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
public SqlSessionFactory customSqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
Properties props = new Properties();
Expand All @@ -989,7 +1049,7 @@ public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
@Configuration
static class CustomSqlSessionTemplateConfiguration {
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
public SqlSessionTemplate customSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
}
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2015-2021 the original author or authors.
Copyright 2015-2022 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -68,7 +68,7 @@

<properties>
<mybatis.version>3.5.9</mybatis.version>
<mybatis-spring.version>2.0.6</mybatis-spring.version>
<mybatis-spring.version>2.0.7-SNAPSHOT</mybatis-spring.version>
<mybatis-freemarker.version>1.2.3</mybatis-freemarker.version>
<mybatis-velocity.version>2.1.1</mybatis-velocity.version>
<mybatis-thymeleaf.version>1.0.3</mybatis-thymeleaf.version>
Expand Down

0 comments on commit ba522d5

Please sign in to comment.