It is recommended to add XmlConfigBuilder to support Configuration construction parameters

https://github.com/mybatis/mybatis-3/blob/master/src/main/java/org/apache/ibatis/builder/xml/XMLConfigBuilder.java#L85,L92

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

Comment From: brucelwl

@harawata

Comment From: harawata

Hello @brucelwl ,

What are you trying to achieve? Can't you perform additional configuration on the Configuration instance returned from XMLConfigBuilder#parse() ?

Configuration must be loaded in a particular order, so passing a partially loaded Configuration instance might not work as you expect.

Comment From: brucelwl

@harawata I wrote a subclass of configuration so that we can use decorator mode to implement interceptors and improve code performance, but I found that Configuration in XMLConfigBuilder is fixed, At present, my approach is to modify the Configuration object by reflection

my code:

public class InterceptorChain {

    private final List<InterceptedMarker> interceptors = new ArrayList<>();

    public InterceptorChain() {
    }

    public boolean addInterceptor(Interceptor interceptor) {
        if (interceptor instanceof InterceptedMarker) {
            interceptors.add((InterceptedMarker) interceptor);
            return true;
        }
        return false;
    }

    /**
     * target must be an implementation of T or its subclass
     */
    @SuppressWarnings("unchecked")
    public <T> T buildChain(T target, Class<T> tClass) {

        List<InterceptedMarker> executorInterceptors = interceptors.stream()
                .filter(item -> tClass.isAssignableFrom(item.getClass())).collect(Collectors.toList());

        if (executorInterceptors.size() == 0) {
            return target;
        }

        InterceptedMarker first = executorInterceptors.get(0);
        InterceptedMarker next = first;

        for (int i = 1; i < executorInterceptors.size(); i++) {
            InterceptedMarker interceptorMarker = executorInterceptors.get(i);
            next.setNext(interceptorMarker);
            next = interceptorMarker;
        }
        next.setNext(target);
        return (T) first;
    }


}
public class OptimizedConfiguration extends Configuration {

    protected InterceptorChain interceptorChain = new InterceptorChain();

    @Override
    public void addInterceptor(Interceptor interceptor) {
        if (!interceptorChain.addInterceptor(interceptor)) {
            super.addInterceptor(interceptor);
        }
    }

    @Override
    public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
        ParameterHandler parameterHandler = super.newParameterHandler(mappedStatement, parameterObject, boundSql);

        parameterHandler = interceptorChain.buildChain(parameterHandler, ParameterHandler.class);

        return parameterHandler;
    }

    @Override
    public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) {
        ResultSetHandler resultSetHandler = super.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);

        resultSetHandler = interceptorChain.buildChain(resultSetHandler, ResultSetHandler.class);

        return resultSetHandler;
    }

    @Override
    public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
        StatementHandler statementHandler = super.newStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);

        statementHandler = interceptorChain.buildChain(statementHandler, StatementHandler.class);

        return statementHandler;
    }

    @Override
    public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
        Executor executor = super.newExecutor(transaction, executorType);

        executor = interceptorChain.buildChain(executor, Executor.class);

        return executor;
    }
}

public class OptimizedSqlSessionFactoryBuilder extends SqlSessionFactoryBuilder {

    @Override
    public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
            replaceConfiguration(parser, properties);

            return build(parser.parse());
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
            ErrorContext.instance().reset();
            try {
                reader.close();
            } catch (IOException e) {
                // Intentionally ignore. Prefer previous error.
            }
        }
    }

    @Override
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            replaceConfiguration(parser, properties);

            return build(parser.parse());
        } catch (Exception e) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", e);
        } finally {
            ErrorContext.instance().reset();
            try {
                inputStream.close();
            } catch (IOException e) {
                // Intentionally ignore. Prefer previous error.
            }
        }
    }

    // Modify Configuration  to OptimizedConfiguration  by reflection
    private void replaceConfiguration(XMLConfigBuilder parser, Properties properties) {

        OptimizedConfiguration optimizedConfiguration = new OptimizedConfiguration();
        optimizedConfiguration.setVariables(properties);

        Field configurationField = ReflectionUtils.findField(XMLConfigBuilder.class, "configuration");
        ReflectionUtils.makeAccessible(configurationField);
        ReflectionUtils.setField(configurationField, parser, optimizedConfiguration);

        Field typeAliasRegistryField = ReflectionUtils.findField(XMLConfigBuilder.class, "typeAliasRegistry");
        ReflectionUtils.makeAccessible(typeAliasRegistryField);
        ReflectionUtils.setField(typeAliasRegistryField, parser, optimizedConfiguration.getTypeAliasRegistry());

        Field typeHandlerRegistryField = ReflectionUtils.findField(XMLConfigBuilder.class, "typeHandlerRegistry");
        ReflectionUtils.makeAccessible(typeHandlerRegistryField);
        ReflectionUtils.setField(typeHandlerRegistryField, parser, optimizedConfiguration.getTypeHandlerRegistry());

    }

}

Comment From: harawata

@brucelwl ,

That usage is out of scope, I'm afraid. We might reconsider in the future, but please continue using reflection for now if the hack is absolutely necessary.