View Javadoc
1   /*
2    *    Copyright 2009-2024 the original author or authors.
3    *
4    *    Licensed under the Apache License, Version 2.0 (the "License");
5    *    you may not use this file except in compliance with the License.
6    *    You may obtain a copy of the License at
7    *
8    *       https://www.apache.org/licenses/LICENSE-2.0
9    *
10   *    Unless required by applicable law or agreed to in writing, software
11   *    distributed under the License is distributed on an "AS IS" BASIS,
12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *    See the License for the specific language governing permissions and
14   *    limitations under the License.
15   */
16  package org.apache.ibatis.builder;
17  
18  import static com.googlecode.catchexception.apis.BDDCatchException.caughtException;
19  import static com.googlecode.catchexception.apis.BDDCatchException.when;
20  import static org.assertj.core.api.Assertions.assertThat;
21  import static org.assertj.core.api.BDDAssertions.then;
22  import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
23  
24  import java.io.InputStream;
25  import java.util.regex.Pattern;
26  
27  import org.apache.ibatis.builder.xml.XMLMapperBuilder;
28  import org.apache.ibatis.io.Resources;
29  import org.apache.ibatis.mapping.MappedStatement;
30  import org.apache.ibatis.mapping.ResultSetType;
31  import org.apache.ibatis.mapping.StatementType;
32  import org.apache.ibatis.session.Configuration;
33  import org.apache.ibatis.type.TypeHandler;
34  import org.junit.jupiter.api.Assertions;
35  import org.junit.jupiter.api.Test;
36  
37  class XmlMapperBuilderTest {
38  
39    @Test
40    void shouldSuccessfullyLoadXMLMapperFile() {
41      assertDoesNotThrow(() -> {
42        Configuration configuration = new Configuration();
43        String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
44        try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
45          XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
46              configuration.getSqlFragments());
47          builder.parse();
48        }
49      });
50    }
51  
52    @Test
53    void mappedStatementWithOptions() throws Exception {
54      Configuration configuration = new Configuration();
55      String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
56      try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
57        XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
58            configuration.getSqlFragments());
59        builder.parse();
60  
61        MappedStatement mappedStatement = configuration.getMappedStatement("selectWithOptions");
62        assertThat(mappedStatement.getFetchSize()).isEqualTo(200);
63        assertThat(mappedStatement.getTimeout()).isEqualTo(10);
64        assertThat(mappedStatement.getStatementType()).isEqualTo(StatementType.PREPARED);
65        assertThat(mappedStatement.getResultSetType()).isEqualTo(ResultSetType.SCROLL_SENSITIVE);
66        assertThat(mappedStatement.isFlushCacheRequired()).isFalse();
67        assertThat(mappedStatement.isUseCache()).isFalse();
68      }
69    }
70  
71    @Test
72    void mappedStatementWithoutOptionsWhenSpecifyDefaultValue() throws Exception {
73      Configuration configuration = new Configuration();
74      configuration.setDefaultResultSetType(ResultSetType.SCROLL_INSENSITIVE);
75      String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
76      InputStream inputStream = Resources.getResourceAsStream(resource);
77      XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
78          configuration.getSqlFragments());
79      builder.parse();
80      inputStream.close();
81  
82      MappedStatement mappedStatement = configuration.getMappedStatement("selectAuthor");
83      assertThat(mappedStatement.getResultSetType()).isEqualTo(ResultSetType.SCROLL_INSENSITIVE);
84    }
85  
86    @Test
87    void parseExpression() {
88      BaseBuilder builder = new BaseBuilder(new Configuration()) {
89      };
90      {
91        Pattern pattern = builder.parseExpression("[0-9]", "[a-z]");
92        assertThat(pattern.matcher("0").find()).isTrue();
93        assertThat(pattern.matcher("a").find()).isFalse();
94      }
95      {
96        Pattern pattern = builder.parseExpression(null, "[a-z]");
97        assertThat(pattern.matcher("0").find()).isFalse();
98        assertThat(pattern.matcher("a").find()).isTrue();
99      }
100   }
101 
102   @Test
103   void resolveJdbcTypeWithUndefinedValue() {
104     BaseBuilder builder = new BaseBuilder(new Configuration()) {
105     };
106     when(() -> builder.resolveJdbcType("aaa"));
107     then(caughtException()).isInstanceOf(BuilderException.class)
108         .hasMessageStartingWith("Error resolving JdbcType. Cause: java.lang.IllegalArgumentException: No enum")
109         .hasMessageEndingWith("org.apache.ibatis.type.JdbcType.aaa");
110   }
111 
112   @Test
113   void resolveResultSetTypeWithUndefinedValue() {
114     BaseBuilder builder = new BaseBuilder(new Configuration()) {
115     };
116     when(() -> builder.resolveResultSetType("bbb"));
117     then(caughtException()).isInstanceOf(BuilderException.class)
118         .hasMessageStartingWith("Error resolving ResultSetType. Cause: java.lang.IllegalArgumentException: No enum")
119         .hasMessageEndingWith("org.apache.ibatis.mapping.ResultSetType.bbb");
120   }
121 
122   @Test
123   void resolveParameterModeWithUndefinedValue() {
124     BaseBuilder builder = new BaseBuilder(new Configuration()) {
125     };
126     when(() -> builder.resolveParameterMode("ccc"));
127     then(caughtException()).isInstanceOf(BuilderException.class)
128         .hasMessageStartingWith("Error resolving ParameterMode. Cause: java.lang.IllegalArgumentException: No enum")
129         .hasMessageEndingWith("org.apache.ibatis.mapping.ParameterMode.ccc");
130   }
131 
132   @Test
133   void createInstanceWithAbstractClass() {
134     BaseBuilder builder = new BaseBuilder(new Configuration()) {
135     };
136     when(() -> builder.createInstance("org.apache.ibatis.builder.BaseBuilder"));
137     then(caughtException()).isInstanceOf(BuilderException.class).hasMessage(
138         "Error creating instance. Cause: java.lang.NoSuchMethodException: org.apache.ibatis.builder.BaseBuilder.<init>()");
139   }
140 
141   @Test
142   void resolveClassWithNotFound() {
143     BaseBuilder builder = new BaseBuilder(new Configuration()) {
144     };
145     when(() -> builder.resolveClass("ddd"));
146     then(caughtException()).isInstanceOf(BuilderException.class).hasMessage(
147         "Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'ddd'.  Cause: java.lang.ClassNotFoundException: Cannot find class: ddd");
148   }
149 
150   @Test
151   void resolveTypeHandlerTypeHandlerAliasIsNull() {
152     BaseBuilder builder = new BaseBuilder(new Configuration()) {
153     };
154     TypeHandler<?> typeHandler = builder.resolveTypeHandler(String.class, (String) null);
155     assertThat(typeHandler).isNull();
156   }
157 
158   @Test
159   void resolveTypeHandlerNoAssignable() {
160     BaseBuilder builder = new BaseBuilder(new Configuration()) {
161     };
162     when(() -> builder.resolveTypeHandler(String.class, "integer"));
163     then(caughtException()).isInstanceOf(BuilderException.class).hasMessage(
164         "Type java.lang.Integer is not a valid TypeHandler because it does not implement TypeHandler interface");
165   }
166 
167   @Test
168   void setCurrentNamespaceValueIsNull() {
169     MapperBuilderAssistant builder = new MapperBuilderAssistant(new Configuration(), "resource");
170     when(() -> builder.setCurrentNamespace(null));
171     then(caughtException()).isInstanceOf(BuilderException.class)
172         .hasMessage("The mapper element requires a namespace attribute to be specified.");
173   }
174 
175   @Test
176   void useCacheRefNamespaceIsNull() {
177     MapperBuilderAssistant builder = new MapperBuilderAssistant(new Configuration(), "resource");
178     when(() -> builder.useCacheRef(null));
179     then(caughtException()).isInstanceOf(BuilderException.class)
180         .hasMessage("cache-ref element requires a namespace attribute.");
181   }
182 
183   @Test
184   void useCacheRefNamespaceIsUndefined() {
185     MapperBuilderAssistant builder = new MapperBuilderAssistant(new Configuration(), "resource");
186     when(() -> builder.useCacheRef("eee"));
187     then(caughtException()).hasMessage("No cache for namespace 'eee' could be found.");
188   }
189 
190   @Test
191   void shouldFailedLoadXMLMapperFile() throws Exception {
192     Configuration configuration = new Configuration();
193     String resource = "org/apache/ibatis/builder/ProblemMapper.xml";
194     try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
195       XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
196           configuration.getSqlFragments());
197       Exception exception = Assertions.assertThrows(BuilderException.class, builder::parse);
198       Assertions.assertTrue(exception.getMessage()
199           .contains("Error parsing Mapper XML. The XML location is 'org/apache/ibatis/builder/ProblemMapper.xml'"));
200     }
201   }
202 
203   // @Test
204   // public void shouldNotLoadTheSameNamespaceFromTwoResourcesWithDifferentNames() throws Exception {
205   // Configuration configuration = new Configuration();
206   // String resource = "org/apache/ibatis/builder/AuthorMapper.xml";
207   // InputStream inputStream = Resources.getResourceAsStream(resource);
208   // XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, "name1",
209   // configuration.getSqlFragments());
210   // builder.parse();
211   // InputStream inputStream2 = Resources.getResourceAsStream(resource);
212   // XMLMapperBuilder builder2 = new XMLMapperBuilder(inputStream2, configuration, "name2",
213   // configuration.getSqlFragments());
214   // builder2.parse();
215   // }
216 
217   @Test
218   void errorResultMapLocation() throws Exception {
219     Configuration configuration = new Configuration();
220     String resource = "org/apache/ibatis/builder/ProblemResultMapper.xml";
221     try (InputStream inputStream = Resources.getResourceAsStream(resource)) {
222       XMLMapperBuilder builder = new XMLMapperBuilder(inputStream, configuration, resource,
223           configuration.getSqlFragments());
224       builder.parse();
225       String resultMapName = "java.lang.String";
226       // namespace + "." + id
227       String statementId = "org.mybatis.spring.ErrorProblemMapper.findProblemResultMapTest";
228       // same as MapperBuilderAssistant.getStatementResultMaps Exception message
229       String message = "Could not find result map '" + resultMapName + "' referenced from '" + statementId + "'";
230       IncompleteElementException exception = Assertions.assertThrows(IncompleteElementException.class,
231           () -> configuration.getMappedStatement("findProblemTypeTest"));
232       assertThat(exception.getMessage()).isEqualTo(message);
233     }
234   }
235 }