mybatis / spring-boot-starter

MyBatis integration with Spring Boot
Apache License 2.0
4.15k stars 1.79k forks source link

Incompatible type between Configuration SqlSessionFactoryBean and MybatisProperties #959

Closed szopal closed 4 months ago

szopal commented 7 months ago

After upgrade mybatis version to 3.0.3 I can't customize SqlSessionFactory because I can't set mybatis properties configuration like I did in 2.3.1

@Bean
@ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
public SqlSessionFactory sqlSessionFactoryBean(final MybatisProperties properties) throws Exception {
  final SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
  [...here is some of my code...]
  factoryBean.setConfiguration(properties.getConfiguration());
  return factoryBean.getObject();
}

There is error:

image

harawata commented 7 months ago

Hello @szopal ,

I moved the issue to mybais-spring-boot-starter repo.

See if ConfigurationCustomizer or SqlSessionFactoryBeanCustomizer helps.

There also seems to be a case that is not covered currently. See #928 .

If none of the above helps, please elaborate on the usage details.

szopal commented 7 months ago

I'm not sure if you understand me - In previous version (2.x) I customize SqlSessionFactory like this:

@Bean
  @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
  public SqlSessionFactory sqlSessionFactoryBean(final MybatisProperties properties) throws Exception {
    final SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setMapperLocations();
    Resource[] mappers;
    final Resource[] resource1 = new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mappers/*.xml");
    try {
      final Resource[] resource2 = new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/batch/mappers/*.xml");
      mappers = ArrayUtils.addAll(resource1, resource2);
    } catch (final FileNotFoundException fnfe) {
      mappers = resource1;
    }
    factoryBean.setMapperLocations(mappers);
    factoryBean.setTypeAliasesPackage("app.core.repository.enumhandler"); =
    factoryBean.setTypeHandlersPackage("app.repository.typehandler");
    factoryBean.setConfiguration(properties.getConfiguration());
    return factoryBean.getObject();
  }

The main part of code is:

factoryBean.setConfiguration(properties.getConfiguration());

But now, I have to do like this:

  @Bean
  @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX)
  public SqlSessionFactory sqlSessionFactoryBean(final MybatisProperties properties) throws Exception {
    final SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource);
    factoryBean.setMapperLocations();
    Resource[] mappers;
    final Resource[] resource1 = new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/mappers/*.xml");
    try {
      final Resource[] resource2 = new PathMatchingResourcePatternResolver().getResources("classpath:mybatis/batch/mappers/*.xml");
      mappers = ArrayUtils.addAll(resource1, resource2);
    } catch (final FileNotFoundException fnfe) {
      mappers = resource1;
    }
    factoryBean.setMapperLocations(mappers);
    factoryBean.setTypeAliasesPackage("app.core.repository.enumhandler");
    factoryBean.setTypeHandlersPackage("app.repository.typehandler");
    if (properties.getConfiguration() != null) {
      // @formatter:off
      final Configuration configuration = new Configuration();
      configuration.setCacheEnabled(Optional.ofNullable(properties.getConfiguration().getCacheEnabled()).orElse(Boolean.FALSE));
      configuration.setDefaultFetchSize(properties.getConfiguration().getDefaultFetchSize());
      configuration.setDefaultEnumTypeHandler(properties.getConfiguration().getDefaultEnumTypeHandler());
      configuration.setDefaultExecutorType(properties.getConfiguration().getDefaultExecutorType());
      configuration.setJdbcTypeForNull(properties.getConfiguration().getJdbcTypeForNull());
      configuration.setMapUnderscoreToCamelCase(Optional.ofNullable(properties.getConfiguration().getMapUnderscoreToCamelCase()).orElse(Boolean.FALSE));
      configuration.setReturnInstanceForEmptyRow(Optional.ofNullable(properties.getConfiguration().getReturnInstanceForEmptyRow()).orElse(Boolean.FALSE));
      configuration.setUseColumnLabel(Optional.ofNullable(properties.getConfiguration().getUseColumnLabel()).orElse(Boolean.FALSE));
      configuration.setUseGeneratedKeys(Optional.ofNullable(properties.getConfiguration().getUseGeneratedKeys()).orElse(Boolean.FALSE));
      // @formatter:on

      factoryBean.setConfiguration(configuration);
    }
    return factoryBean.getObject();
  }

Because configuration from MybatisProperties is different type and it can't be rewrite automatically. But, maybe I do something wrong - If yes, please let me know.

jeffgbutler commented 7 months ago

This changed in 3.0. There's a more concise way to write your code:

if (properties.getConfiguration() != null) {
    final Configuration configuration = new Configuration();
    properties.getConfiguration().applyTo(configuration);
    factoryBean.setConfiguration(configuration);
}
szopal commented 7 months ago

Thank very much! Now I can see it's changed in 3.0.

hazendaz commented 4 months ago

closing issue as seems resolved.