/** * Copyright 2009-2017 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ibatis.builder; import java.io.InputStream; import java.io.StringReader; import java.math.RoundingMode; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.HashSet; import java.util.Properties; import java.util.Set; import org.apache.ibatis.builder.mapper.CustomMapper; import org.apache.ibatis.builder.typehandler.CustomIntegerTypeHandler; import org.apache.ibatis.builder.xml.XMLConfigBuilder; import org.apache.ibatis.datasource.unpooled.UnpooledDataSource; import org.apache.ibatis.domain.blog.Author; import org.apache.ibatis.domain.blog.Blog; import org.apache.ibatis.domain.blog.mappers.BlogMapper; import org.apache.ibatis.domain.blog.mappers.NestedBlogMapper; import org.apache.ibatis.domain.jpetstore.Cart; import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory; import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory; import org.apache.ibatis.io.JBoss6VFS; import org.apache.ibatis.io.Resources; import org.apache.ibatis.logging.slf4j.Slf4jImpl; import org.apache.ibatis.mapping.Environment; import org.apache.ibatis.scripting.defaults.RawLanguageDriver; import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver; import org.apache.ibatis.session.AutoMappingBehavior; import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.LocalCacheScope; import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory; import org.apache.ibatis.type.BaseTypeHandler; import org.apache.ibatis.type.EnumOrdinalTypeHandler; import org.apache.ibatis.type.EnumTypeHandler; import org.apache.ibatis.type.JdbcType; import org.apache.ibatis.type.TypeHandler; import org.apache.ibatis.type.TypeHandlerRegistry; import org.junit.Test; import static com.googlecode.catchexception.apis.BDDCatchException.*; import static org.assertj.core.api.BDDAssertions.then; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertArrayEquals; public class XmlConfigBuilderTest { @Test public void shouldSuccessfullyLoadMinimalXMLConfigFile() throws Exception { String resource = "org/apache/ibatis/builder/MinimalMapperConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); XMLConfigBuilder builder = new XMLConfigBuilder(inputStream); Configuration config = builder.parse(); assertNotNull(config); assertThat(config.getAutoMappingBehavior()).isEqualTo(AutoMappingBehavior.PARTIAL); assertThat(config.getAutoMappingUnknownColumnBehavior()).isEqualTo(AutoMappingUnknownColumnBehavior.NONE); assertThat(config.isCacheEnabled()).isTrue(); assertThat(config.getProxyFactory()).isInstanceOf(JavassistProxyFactory.class); assertThat(config.isLazyLoadingEnabled()).isFalse(); assertThat(config.isAggressiveLazyLoading()).isFalse(); assertThat(config.isMultipleResultSetsEnabled()).isTrue(); assertThat(config.isUseColumnLabel()).isTrue(); assertThat(config.isUseGeneratedKeys()).isFalse(); assertThat(config.getDefaultExecutorType()).isEqualTo(ExecutorType.SIMPLE); assertNull(config.getDefaultStatementTimeout()); assertNull(config.getDefaultFetchSize()); assertThat(config.isMapUnderscoreToCamelCase()).isFalse(); assertThat(config.isSafeRowBoundsEnabled()).isFalse(); assertThat(config.getLocalCacheScope()).isEqualTo(LocalCacheScope.SESSION); assertThat(config.getJdbcTypeForNull()).isEqualTo(JdbcType.OTHER); assertThat(config.getLazyLoadTriggerMethods()).isEqualTo((Set<String>) new HashSet<String>(Arrays.asList("equals", "clone", "hashCode", "toString"))); assertThat(config.isSafeResultHandlerEnabled()).isTrue(); assertThat(config.getDefaultScriptingLanuageInstance()).isInstanceOf(XMLLanguageDriver.class); assertThat(config.isCallSettersOnNulls()).isFalse(); assertNull(config.getLogPrefix()); assertNull(config.getLogImpl()); assertNull(config.getConfigurationFactory()); assertThat(config.getTypeHandlerRegistry().getTypeHandler(RoundingMode.class)).isInstanceOf(EnumTypeHandler.class); inputStream.close(); } enum MyEnum { ONE, TWO } public static class EnumOrderTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> { private E[] constants; public EnumOrderTypeHandler(Class<E> javaType) { constants = javaType.getEnumConstants(); } @Override public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException { ps.setInt(i, parameter.ordinal() + 1); // 0 means NULL so add +1 } @Override public E getNullableResult(ResultSet rs, String columnName) throws SQLException { int index = rs.getInt(columnName) - 1; return index < 0 ? null : constants[index]; } @Override public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException { int index = rs.getInt(rs.getInt(columnIndex)) - 1; return index < 0 ? null : constants[index]; } @Override public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { int index = cs.getInt(columnIndex) - 1; return index < 0 ? null : constants[index]; } } @Test public void registerJavaTypeInitializingTypeHandler() { final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n" + "<configuration>\n" + " <typeHandlers>\n" + " <typeHandler javaType=\"org.apache.ibatis.builder.XmlConfigBuilderTest$MyEnum\"\n" + " handler=\"org.apache.ibatis.builder.XmlConfigBuilderTest$EnumOrderTypeHandler\"/>\n" + " </typeHandlers>\n" + "</configuration>\n"; XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG)); builder.parse(); TypeHandlerRegistry typeHandlerRegistry = builder.getConfiguration().getTypeHandlerRegistry(); TypeHandler<MyEnum> typeHandler = typeHandlerRegistry.getTypeHandler(MyEnum.class); assertTrue(typeHandler instanceof EnumOrderTypeHandler); assertArrayEquals(MyEnum.values(), ((EnumOrderTypeHandler) typeHandler).constants); } @Test public void shouldSuccessfullyLoadXMLConfigFile() throws Exception { String resource = "org/apache/ibatis/builder/CustomizedSettingsMapperConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); Properties props = new Properties(); props.put("prop2", "cccc"); XMLConfigBuilder builder = new XMLConfigBuilder(inputStream, null, props); Configuration config = builder.parse(); assertThat(config.getAutoMappingBehavior()).isEqualTo(AutoMappingBehavior.NONE); assertThat(config.getAutoMappingUnknownColumnBehavior()).isEqualTo(AutoMappingUnknownColumnBehavior.WARNING); assertThat(config.isCacheEnabled()).isFalse(); assertThat(config.getProxyFactory()).isInstanceOf(CglibProxyFactory.class); assertThat(config.isLazyLoadingEnabled()).isTrue(); assertThat(config.isAggressiveLazyLoading()).isTrue(); assertThat(config.isMultipleResultSetsEnabled()).isFalse(); assertThat(config.isUseColumnLabel()).isFalse(); assertThat(config.isUseGeneratedKeys()).isTrue(); assertThat(config.getDefaultExecutorType()).isEqualTo(ExecutorType.BATCH); assertThat(config.getDefaultStatementTimeout()).isEqualTo(10); assertThat(config.getDefaultFetchSize()).isEqualTo(100); assertThat(config.isMapUnderscoreToCamelCase()).isTrue(); assertThat(config.isSafeRowBoundsEnabled()).isTrue(); assertThat(config.getLocalCacheScope()).isEqualTo(LocalCacheScope.STATEMENT); assertThat(config.getJdbcTypeForNull()).isEqualTo(JdbcType.NULL); assertThat(config.getLazyLoadTriggerMethods()).isEqualTo((Set<String>) new HashSet<String>(Arrays.asList("equals", "clone", "hashCode", "toString", "xxx"))); assertThat(config.isSafeResultHandlerEnabled()).isFalse(); assertThat(config.getDefaultScriptingLanuageInstance()).isInstanceOf(RawLanguageDriver.class); assertThat(config.isCallSettersOnNulls()).isTrue(); assertThat(config.getLogPrefix()).isEqualTo("mybatis_"); assertThat(config.getLogImpl().getName()).isEqualTo(Slf4jImpl.class.getName()); assertThat(config.getVfsImpl().getName()).isEqualTo(JBoss6VFS.class.getName()); assertThat(config.getConfigurationFactory().getName()).isEqualTo(String.class.getName()); assertTrue(config.getTypeAliasRegistry().getTypeAliases().get("blogauthor").equals(Author.class)); assertTrue(config.getTypeAliasRegistry().getTypeAliases().get("blog").equals(Blog.class)); assertTrue(config.getTypeAliasRegistry().getTypeAliases().get("cart").equals(Cart.class)); assertThat(config.getTypeHandlerRegistry().getTypeHandler(Integer.class)).isInstanceOf(CustomIntegerTypeHandler.class); assertThat(config.getTypeHandlerRegistry().getTypeHandler(Long.class)).isInstanceOf(CustomLongTypeHandler.class); assertThat(config.getTypeHandlerRegistry().getTypeHandler(String.class)).isInstanceOf(CustomStringTypeHandler.class); assertThat(config.getTypeHandlerRegistry().getTypeHandler(String.class, JdbcType.VARCHAR)).isInstanceOf(CustomStringTypeHandler.class); assertThat(config.getTypeHandlerRegistry().getTypeHandler(RoundingMode.class)).isInstanceOf(EnumOrdinalTypeHandler.class); ExampleObjectFactory objectFactory = (ExampleObjectFactory)config.getObjectFactory(); assertThat(objectFactory.getProperties().size()).isEqualTo(1); assertThat(objectFactory.getProperties().getProperty("objectFactoryProperty")).isEqualTo("100"); assertThat(config.getObjectWrapperFactory()).isInstanceOf(CustomObjectWrapperFactory.class); assertThat(config.getReflectorFactory()).isInstanceOf(CustomReflectorFactory.class); ExamplePlugin plugin = (ExamplePlugin)config.getInterceptors().get(0); assertThat(plugin.getProperties().size()).isEqualTo(1); assertThat(plugin.getProperties().getProperty("pluginProperty")).isEqualTo("100"); Environment environment = config.getEnvironment(); assertThat(environment.getId()).isEqualTo("development"); assertThat(environment.getDataSource()).isInstanceOf(UnpooledDataSource.class); assertThat(environment.getTransactionFactory()).isInstanceOf(JdbcTransactionFactory.class); assertThat(config.getDatabaseId()).isEqualTo("derby"); assertThat(config.getMapperRegistry().getMappers().size()).isEqualTo(4); assertThat(config.getMapperRegistry().hasMapper(CachedAuthorMapper.class)).isTrue(); assertThat(config.getMapperRegistry().hasMapper(CustomMapper.class)).isTrue(); assertThat(config.getMapperRegistry().hasMapper(BlogMapper.class)).isTrue(); assertThat(config.getMapperRegistry().hasMapper(NestedBlogMapper.class)).isTrue(); inputStream.close(); } @Test public void shouldSuccessfullyLoadXMLConfigFileWithPropertiesUrl() throws Exception { String resource = "org/apache/ibatis/builder/PropertiesUrlMapperConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); XMLConfigBuilder builder = new XMLConfigBuilder(inputStream); Configuration config = builder.parse(); assertThat(config.getVariables().get("driver").toString()).isEqualTo("org.apache.derby.jdbc.EmbeddedDriver"); assertThat(config.getVariables().get("prop1").toString()).isEqualTo("bbbb"); inputStream.close(); } @Test public void parseIsTwice() throws Exception { String resource = "org/apache/ibatis/builder/MinimalMapperConfig.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); XMLConfigBuilder builder = new XMLConfigBuilder(inputStream); builder.parse(); when(builder).parse(); then(caughtException()).isInstanceOf(BuilderException.class) .hasMessage("Each XMLConfigBuilder can only be used once."); inputStream.close(); } @Test public void unknownSettings() { final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n" + "<configuration>\n" + " <settings>\n" + " <setting name=\"foo\" value=\"bar\"/>\n" + " </settings>\n" + "</configuration>\n"; XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG)); when(builder).parse(); then(caughtException()).isInstanceOf(BuilderException.class) .hasMessageContaining("The setting foo is not known. Make sure you spelled it correctly (case sensitive)."); } @Test public void unknownJavaTypeOnTypeHandler() { final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n" + "<configuration>\n" + " <typeAliases>\n" + " <typeAlias type=\"a.b.c.Foo\"/>\n" + " </typeAliases>\n" + "</configuration>\n"; XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG)); when(builder).parse(); then(caughtException()).isInstanceOf(BuilderException.class) .hasMessageContaining("Error registering typeAlias for 'null'. Cause: "); } @Test public void propertiesSpecifyResourceAndUrlAtSameTime() { final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n" + "<configuration>\n" + " <properties resource=\"a/b/c/foo.properties\" url=\"file:./a/b/c/jdbc.properties\"/>\n" + "</configuration>\n"; XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG)); when(builder).parse(); then(caughtException()).isInstanceOf(BuilderException.class) .hasMessageContaining("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other."); } }