1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.builder;
17
18 import static com.googlecode.catchexception.apis.BDDCatchException.*;
19 import static org.assertj.core.api.Assertions.assertThat;
20 import static org.assertj.core.api.BDDAssertions.then;
21 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22 import static org.junit.jupiter.api.Assertions.assertNotNull;
23 import static org.junit.jupiter.api.Assertions.assertNull;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.io.InputStream;
27 import java.io.StringReader;
28 import java.math.RoundingMode;
29 import java.sql.CallableStatement;
30 import java.sql.PreparedStatement;
31 import java.sql.ResultSet;
32 import java.sql.SQLException;
33 import java.util.Arrays;
34 import java.util.HashSet;
35 import java.util.Properties;
36
37 import org.apache.ibatis.builder.mapper.CustomMapper;
38 import org.apache.ibatis.builder.typehandler.CustomIntegerTypeHandler;
39 import org.apache.ibatis.builder.xml.XMLConfigBuilder;
40 import org.apache.ibatis.datasource.unpooled.UnpooledDataSource;
41 import org.apache.ibatis.domain.blog.Author;
42 import org.apache.ibatis.domain.blog.Blog;
43 import org.apache.ibatis.domain.blog.mappers.BlogMapper;
44 import org.apache.ibatis.domain.blog.mappers.NestedBlogMapper;
45 import org.apache.ibatis.domain.jpetstore.Cart;
46 import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;
47 import org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory;
48 import org.apache.ibatis.io.JBoss6VFS;
49 import org.apache.ibatis.io.Resources;
50 import org.apache.ibatis.logging.slf4j.Slf4jImpl;
51 import org.apache.ibatis.mapping.Environment;
52 import org.apache.ibatis.mapping.ResultSetType;
53 import org.apache.ibatis.scripting.defaults.RawLanguageDriver;
54 import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
55 import org.apache.ibatis.session.AutoMappingBehavior;
56 import org.apache.ibatis.session.AutoMappingUnknownColumnBehavior;
57 import org.apache.ibatis.session.Configuration;
58 import org.apache.ibatis.session.ExecutorType;
59 import org.apache.ibatis.session.LocalCacheScope;
60 import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
61 import org.apache.ibatis.type.BaseTypeHandler;
62 import org.apache.ibatis.type.EnumOrdinalTypeHandler;
63 import org.apache.ibatis.type.EnumTypeHandler;
64 import org.apache.ibatis.type.JdbcType;
65 import org.apache.ibatis.type.TypeHandler;
66 import org.apache.ibatis.type.TypeHandlerRegistry;
67 import org.junit.jupiter.api.Tag;
68 import org.junit.jupiter.api.Test;
69
70 class XmlConfigBuilderTest {
71
72 @Test
73 void shouldSuccessfullyLoadMinimalXMLConfigFile() throws Exception {
74 String resource = "org/apache/ibatis/builder/MinimalMapperConfig.xml";
75 try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
76 XMLConfigBuilder builder = new XMLConfigBuilder(inputStream);
77 Configuration config = builder.parse();
78 assertNotNull(config);
79 assertThat(config.getAutoMappingBehavior()).isEqualTo(AutoMappingBehavior.PARTIAL);
80 assertThat(config.getAutoMappingUnknownColumnBehavior()).isEqualTo(AutoMappingUnknownColumnBehavior.NONE);
81 assertThat(config.isCacheEnabled()).isTrue();
82 assertThat(config.getProxyFactory()).isInstanceOf(JavassistProxyFactory.class);
83 assertThat(config.isLazyLoadingEnabled()).isFalse();
84 assertThat(config.isAggressiveLazyLoading()).isFalse();
85 assertThat(config.isMultipleResultSetsEnabled()).isTrue();
86 assertThat(config.isUseColumnLabel()).isTrue();
87 assertThat(config.isUseGeneratedKeys()).isFalse();
88 assertThat(config.getDefaultExecutorType()).isEqualTo(ExecutorType.SIMPLE);
89 assertNull(config.getDefaultStatementTimeout());
90 assertNull(config.getDefaultFetchSize());
91 assertNull(config.getDefaultResultSetType());
92 assertThat(config.isMapUnderscoreToCamelCase()).isFalse();
93 assertThat(config.isSafeRowBoundsEnabled()).isFalse();
94 assertThat(config.getLocalCacheScope()).isEqualTo(LocalCacheScope.SESSION);
95 assertThat(config.getJdbcTypeForNull()).isEqualTo(JdbcType.OTHER);
96 assertThat(config.getLazyLoadTriggerMethods()).isEqualTo(new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString")));
97 assertThat(config.isSafeResultHandlerEnabled()).isTrue();
98 assertThat(config.getDefaultScriptingLanuageInstance()).isInstanceOf(XMLLanguageDriver.class);
99 assertThat(config.isCallSettersOnNulls()).isFalse();
100 assertNull(config.getLogPrefix());
101 assertNull(config.getLogImpl());
102 assertNull(config.getConfigurationFactory());
103 assertThat(config.getTypeHandlerRegistry().getTypeHandler(RoundingMode.class)).isInstanceOf(EnumTypeHandler.class);
104 assertThat(config.isShrinkWhitespacesInSql()).isFalse();
105 assertThat(config.isArgNameBasedConstructorAutoMapping()).isFalse();
106 assertThat(config.getDefaultSqlProviderType()).isNull();
107 assertThat(config.isNullableOnForEach()).isFalse();
108 }
109 }
110
111 enum MyEnum {
112 ONE, TWO
113 }
114
115 public static class EnumOrderTypeHandler<E extends Enum<E>> extends BaseTypeHandler<E> {
116
117 private E[] constants;
118
119 public EnumOrderTypeHandler(Class<E> javaType) {
120 constants = javaType.getEnumConstants();
121 }
122
123 @Override
124 public void setNonNullParameter(PreparedStatement ps, int i, E parameter, JdbcType jdbcType) throws SQLException {
125 ps.setInt(i, parameter.ordinal() + 1);
126 }
127
128 @Override
129 public E getNullableResult(ResultSet rs, String columnName) throws SQLException {
130 int index = rs.getInt(columnName) - 1;
131 return index < 0 ? null : constants[index];
132 }
133
134 @Override
135 public E getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
136 int index = rs.getInt(rs.getInt(columnIndex)) - 1;
137 return index < 0 ? null : constants[index];
138 }
139
140 @Override
141 public E getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
142 int index = cs.getInt(columnIndex) - 1;
143 return index < 0 ? null : constants[index];
144 }
145 }
146
147 @Test
148 void registerJavaTypeInitializingTypeHandler() {
149 final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
150 + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n"
151 + "<configuration>\n"
152 + " <typeHandlers>\n"
153 + " <typeHandler javaType=\"org.apache.ibatis.builder.XmlConfigBuilderTest$MyEnum\"\n"
154 + " handler=\"org.apache.ibatis.builder.XmlConfigBuilderTest$EnumOrderTypeHandler\"/>\n"
155 + " </typeHandlers>\n"
156 + "</configuration>\n";
157
158 XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG));
159 builder.parse();
160
161 TypeHandlerRegistry typeHandlerRegistry = builder.getConfiguration().getTypeHandlerRegistry();
162 TypeHandler<MyEnum> typeHandler = typeHandlerRegistry.getTypeHandler(MyEnum.class);
163
164 assertTrue(typeHandler instanceof EnumOrderTypeHandler);
165 assertArrayEquals(MyEnum.values(), ((EnumOrderTypeHandler<MyEnum>) typeHandler).constants);
166 }
167
168 @Tag("RequireIllegalAccess")
169 @Test
170 void shouldSuccessfullyLoadXMLConfigFile() throws Exception {
171 String resource = "org/apache/ibatis/builder/CustomizedSettingsMapperConfig.xml";
172 try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
173 Properties props = new Properties();
174 props.put("prop2", "cccc");
175 XMLConfigBuilder builder = new XMLConfigBuilder(inputStream, null, props);
176 Configuration config = builder.parse();
177
178 assertThat(config.getAutoMappingBehavior()).isEqualTo(AutoMappingBehavior.NONE);
179 assertThat(config.getAutoMappingUnknownColumnBehavior()).isEqualTo(AutoMappingUnknownColumnBehavior.WARNING);
180 assertThat(config.isCacheEnabled()).isFalse();
181 assertThat(config.getProxyFactory()).isInstanceOf(CglibProxyFactory.class);
182 assertThat(config.isLazyLoadingEnabled()).isTrue();
183 assertThat(config.isAggressiveLazyLoading()).isTrue();
184 assertThat(config.isMultipleResultSetsEnabled()).isFalse();
185 assertThat(config.isUseColumnLabel()).isFalse();
186 assertThat(config.isUseGeneratedKeys()).isTrue();
187 assertThat(config.getDefaultExecutorType()).isEqualTo(ExecutorType.BATCH);
188 assertThat(config.getDefaultStatementTimeout()).isEqualTo(10);
189 assertThat(config.getDefaultFetchSize()).isEqualTo(100);
190 assertThat(config.getDefaultResultSetType()).isEqualTo(ResultSetType.SCROLL_INSENSITIVE);
191 assertThat(config.isMapUnderscoreToCamelCase()).isTrue();
192 assertThat(config.isSafeRowBoundsEnabled()).isTrue();
193 assertThat(config.getLocalCacheScope()).isEqualTo(LocalCacheScope.STATEMENT);
194 assertThat(config.getJdbcTypeForNull()).isEqualTo(JdbcType.NULL);
195 assertThat(config.getLazyLoadTriggerMethods()).isEqualTo(new HashSet<>(Arrays.asList("equals", "clone", "hashCode", "toString", "xxx")));
196 assertThat(config.isSafeResultHandlerEnabled()).isFalse();
197 assertThat(config.getDefaultScriptingLanuageInstance()).isInstanceOf(RawLanguageDriver.class);
198 assertThat(config.isCallSettersOnNulls()).isTrue();
199 assertThat(config.getLogPrefix()).isEqualTo("mybatis_");
200 assertThat(config.getLogImpl().getName()).isEqualTo(Slf4jImpl.class.getName());
201 assertThat(config.getVfsImpl().getName()).isEqualTo(JBoss6VFS.class.getName());
202 assertThat(config.getConfigurationFactory().getName()).isEqualTo(String.class.getName());
203 assertThat(config.isShrinkWhitespacesInSql()).isTrue();
204 assertThat(config.isArgNameBasedConstructorAutoMapping()).isTrue();
205 assertThat(config.getDefaultSqlProviderType().getName()).isEqualTo(MySqlProvider.class.getName());
206 assertThat(config.isNullableOnForEach()).isTrue();
207
208 assertThat(config.getTypeAliasRegistry().getTypeAliases().get("blogauthor")).isEqualTo(Author.class);
209 assertThat(config.getTypeAliasRegistry().getTypeAliases().get("blog")).isEqualTo(Blog.class);
210 assertThat(config.getTypeAliasRegistry().getTypeAliases().get("cart")).isEqualTo(Cart.class);
211
212 assertThat(config.getTypeHandlerRegistry().getTypeHandler(Integer.class)).isInstanceOf(CustomIntegerTypeHandler.class);
213 assertThat(config.getTypeHandlerRegistry().getTypeHandler(Long.class)).isInstanceOf(CustomLongTypeHandler.class);
214 assertThat(config.getTypeHandlerRegistry().getTypeHandler(String.class)).isInstanceOf(CustomStringTypeHandler.class);
215 assertThat(config.getTypeHandlerRegistry().getTypeHandler(String.class, JdbcType.VARCHAR)).isInstanceOf(CustomStringTypeHandler.class);
216 assertThat(config.getTypeHandlerRegistry().getTypeHandler(RoundingMode.class)).isInstanceOf(EnumOrdinalTypeHandler.class);
217
218 ExampleObjectFactory objectFactory = (ExampleObjectFactory) config.getObjectFactory();
219 assertThat(objectFactory.getProperties().size()).isEqualTo(1);
220 assertThat(objectFactory.getProperties().getProperty("objectFactoryProperty")).isEqualTo("100");
221
222 assertThat(config.getObjectWrapperFactory()).isInstanceOf(CustomObjectWrapperFactory.class);
223
224 assertThat(config.getReflectorFactory()).isInstanceOf(CustomReflectorFactory.class);
225
226 ExamplePlugin plugin = (ExamplePlugin) config.getInterceptors().get(0);
227 assertThat(plugin.getProperties().size()).isEqualTo(1);
228 assertThat(plugin.getProperties().getProperty("pluginProperty")).isEqualTo("100");
229
230 Environment environment = config.getEnvironment();
231 assertThat(environment.getId()).isEqualTo("development");
232 assertThat(environment.getDataSource()).isInstanceOf(UnpooledDataSource.class);
233 assertThat(environment.getTransactionFactory()).isInstanceOf(JdbcTransactionFactory.class);
234
235 assertThat(config.getDatabaseId()).isEqualTo("derby");
236
237 assertThat(config.getMapperRegistry().getMappers().size()).isEqualTo(4);
238 assertThat(config.getMapperRegistry().hasMapper(CachedAuthorMapper.class)).isTrue();
239 assertThat(config.getMapperRegistry().hasMapper(CustomMapper.class)).isTrue();
240 assertThat(config.getMapperRegistry().hasMapper(BlogMapper.class)).isTrue();
241 assertThat(config.getMapperRegistry().hasMapper(NestedBlogMapper.class)).isTrue();
242 }
243 }
244
245 @Test
246 void shouldSuccessfullyLoadXMLConfigFileWithPropertiesUrl() throws Exception {
247 String resource = "org/apache/ibatis/builder/PropertiesUrlMapperConfig.xml";
248 try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
249 XMLConfigBuilder builder = new XMLConfigBuilder(inputStream);
250 Configuration config = builder.parse();
251 assertThat(config.getVariables().get("driver").toString()).isEqualTo("org.apache.derby.jdbc.EmbeddedDriver");
252 assertThat(config.getVariables().get("prop1").toString()).isEqualTo("bbbb");
253 }
254 }
255
256 @Test
257 void parseIsTwice() throws Exception {
258 String resource = "org/apache/ibatis/builder/MinimalMapperConfig.xml";
259 try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
260 XMLConfigBuilder builder = new XMLConfigBuilder(inputStream);
261 builder.parse();
262
263 when(builder::parse);
264 then(caughtException()).isInstanceOf(BuilderException.class)
265 .hasMessage("Each XMLConfigBuilder can only be used once.");
266 }
267 }
268
269 @Test
270 void unknownSettings() {
271 final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
272 + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n"
273 + "<configuration>\n"
274 + " <settings>\n"
275 + " <setting name=\"foo\" value=\"bar\"/>\n"
276 + " </settings>\n"
277 + "</configuration>\n";
278
279 XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG));
280 when(builder::parse);
281 then(caughtException()).isInstanceOf(BuilderException.class)
282 .hasMessageContaining("The setting foo is not known. Make sure you spelled it correctly (case sensitive).");
283 }
284
285 @Test
286 void unknownJavaTypeOnTypeHandler() {
287 final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
288 + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n"
289 + "<configuration>\n"
290 + " <typeAliases>\n"
291 + " <typeAlias type=\"a.b.c.Foo\"/>\n"
292 + " </typeAliases>\n"
293 + "</configuration>\n";
294
295 XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG));
296 when(builder::parse);
297 then(caughtException()).isInstanceOf(BuilderException.class)
298 .hasMessageContaining("Error registering typeAlias for 'null'. Cause: ");
299 }
300
301 @Test
302 void propertiesSpecifyResourceAndUrlAtSameTime() {
303 final String MAPPER_CONFIG = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
304 + "<!DOCTYPE configuration PUBLIC \"-//mybatis.org//DTD Config 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-config.dtd\">\n"
305 + "<configuration>\n"
306 + " <properties resource=\"a/b/c/foo.properties\" url=\"file:./a/b/c/jdbc.properties\"/>\n"
307 + "</configuration>\n";
308
309 XMLConfigBuilder builder = new XMLConfigBuilder(new StringReader(MAPPER_CONFIG));
310 when(builder::parse);
311 then(caughtException()).isInstanceOf(BuilderException.class)
312 .hasMessageContaining("The properties element cannot specify both a URL and a resource based property file reference. Please specify one or the other.");
313 }
314
315 static class MySqlProvider {
316 @SuppressWarnings("unused")
317 public static String provideSql() {
318 return "SELECT 1";
319 }
320 }
321
322 }