View Javadoc
1   /*
2    *    Copyright 2009-2023 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.scripting.defaults;
17  
18  import static org.mockito.ArgumentMatchers.any;
19  import static org.mockito.ArgumentMatchers.anyInt;
20  import static org.mockito.Mockito.doThrow;
21  import static org.mockito.Mockito.mock;
22  import static org.mockito.Mockito.times;
23  import static org.mockito.Mockito.verify;
24  import static org.mockito.Mockito.when;
25  
26  import java.sql.PreparedStatement;
27  import java.sql.SQLException;
28  import java.util.ArrayList;
29  import java.util.Collections;
30  import java.util.HashMap;
31  import java.util.List;
32  
33  import org.apache.ibatis.builder.StaticSqlSource;
34  import org.apache.ibatis.domain.blog.Author;
35  import org.apache.ibatis.domain.blog.Section;
36  import org.apache.ibatis.mapping.BoundSql;
37  import org.apache.ibatis.mapping.MappedStatement;
38  import org.apache.ibatis.mapping.ParameterMapping;
39  import org.apache.ibatis.mapping.ResultMap;
40  import org.apache.ibatis.mapping.ResultMapping;
41  import org.apache.ibatis.mapping.SqlCommandType;
42  import org.apache.ibatis.reflection.DefaultReflectorFactory;
43  import org.apache.ibatis.reflection.MetaObject;
44  import org.apache.ibatis.reflection.ReflectorFactory;
45  import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
46  import org.apache.ibatis.reflection.factory.ObjectFactory;
47  import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
48  import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
49  import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver;
50  import org.apache.ibatis.session.Configuration;
51  import org.apache.ibatis.type.JdbcType;
52  import org.apache.ibatis.type.TypeException;
53  import org.apache.ibatis.type.TypeHandler;
54  import org.apache.ibatis.type.TypeHandlerRegistry;
55  import org.junit.jupiter.api.Assertions;
56  import org.junit.jupiter.api.Test;
57  
58  /**
59   * DefaultParameterHandlerTest
60   *
61   * @author Ryan Lamore
62   */
63  class DefaultParameterHandlerTest {
64  
65    @Test
66    void setParametersThrowsProperException() throws SQLException {
67      final MappedStatement mappedStatement = getMappedStatement();
68      final Object parameterObject = null;
69      final BoundSql boundSql = mock(BoundSql.class);
70  
71      TypeHandler<Object> typeHandler = mock(TypeHandler.class);
72      doThrow(new SQLException("foo")).when(typeHandler).setParameter(any(PreparedStatement.class), anyInt(), any(),
73          any(JdbcType.class));
74      ParameterMapping parameterMapping = new ParameterMapping.Builder(mappedStatement.getConfiguration(), "prop",
75          typeHandler).build();
76      List<ParameterMapping> parameterMappings = Collections.singletonList(parameterMapping);
77      when(boundSql.getParameterMappings()).thenReturn(parameterMappings);
78  
79      DefaultParameterHandler defaultParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject,
80          boundSql);
81  
82      PreparedStatement ps = mock(PreparedStatement.class);
83      try {
84        defaultParameterHandler.setParameters(ps);
85        Assertions.fail("Should have thrown TypeException");
86      } catch (Exception e) {
87        Assertions.assertTrue(e instanceof TypeException, "expected TypeException");
88        Assertions.assertTrue(e.getMessage().contains("mapping: ParameterMapping"));
89      }
90  
91    }
92  
93    MappedStatement getMappedStatement() {
94      final Configuration config = new Configuration();
95      final TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
96      return new MappedStatement.Builder(config, "testSelect", new StaticSqlSource(config, "some select statement"),
97          SqlCommandType.SELECT).resultMaps(new ArrayList<ResultMap>() {
98            private static final long serialVersionUID = 1L;
99  
100           {
101             add(new ResultMap.Builder(config, "testMap", HashMap.class, new ArrayList<ResultMapping>() {
102               private static final long serialVersionUID = 1L;
103 
104               {
105                 add(new ResultMapping.Builder(config, "cOlUmN1", "CoLuMn1", registry.getTypeHandler(Integer.class))
106                     .build());
107               }
108             }).build());
109           }
110         }).build();
111   }
112 
113   @Test
114   void testParameterObjectGetPropertyValueWithAdditionalParameter() throws SQLException {
115     Configuration config = new Configuration();
116     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
117 
118     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
119         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
120 
121     Object parameterObject = 1;
122 
123     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
124       {
125         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
126       }
127     }, parameterObject) {
128       {
129         setAdditionalParameter("id", 2);
130       }
131     };
132 
133     DefaultParameterHandler defaultParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject,
134         boundSql);
135 
136     PreparedStatement ps = mock(PreparedStatement.class);
137 
138     defaultParameterHandler.setParameters(ps);
139 
140     verify(ps, times(1)).setInt(1, 2);
141   }
142 
143   @Test
144   void testParameterObjectGetPropertyValueWithNull() throws SQLException {
145     Configuration config = new Configuration();
146     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
147 
148     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
149         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
150 
151     Object parameterObject = null;
152 
153     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
154       {
155         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
156       }
157     }, parameterObject);
158 
159     DefaultParameterHandler defaultParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject,
160         boundSql);
161 
162     PreparedStatement ps = mock(PreparedStatement.class);
163 
164     defaultParameterHandler.setParameters(ps);
165 
166     verify(ps, times(1)).setNull(1, config.getJdbcTypeForNull().TYPE_CODE);
167   }
168 
169   @Test
170   void testParameterObjectGetPropertyValueWithTypeHandler() throws SQLException {
171     Configuration config = new Configuration();
172     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
173 
174     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
175         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
176 
177     Object parameterObject = 1;
178 
179     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
180       {
181         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
182       }
183     }, parameterObject);
184 
185     DefaultParameterHandler defaultParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject,
186         boundSql);
187 
188     PreparedStatement ps = mock(PreparedStatement.class);
189 
190     defaultParameterHandler.setParameters(ps);
191 
192     verify(ps, times(1)).setInt(1, (Integer) parameterObject);
193   }
194 
195   @Test
196   void testParameterObjectGetPropertyValueWithMetaObject() throws SQLException {
197     Configuration config = new Configuration();
198     TypeHandlerRegistry registry = config.getTypeHandlerRegistry();
199 
200     MappedStatement mappedStatement = new MappedStatement.Builder(config, "testSelect",
201         new StaticSqlSource(config, "some select statement"), SqlCommandType.SELECT).build();
202 
203     Author parameterObject = new Author(-1, "cbegin", "******", "cbegin@nowhere.com", "N/A", Section.NEWS);
204 
205     BoundSql boundSql = new BoundSql(config, "some select statement", new ArrayList<ParameterMapping>() {
206       {
207         add(new ParameterMapping.Builder(config, "id", registry.getTypeHandler(int.class)).build());
208         add(new ParameterMapping.Builder(config, "username", registry.getTypeHandler(String.class)).build());
209         add(new ParameterMapping.Builder(config, "password", registry.getTypeHandler(String.class)).build());
210         add(new ParameterMapping.Builder(config, "email", registry.getTypeHandler(String.class)).build());
211         add(new ParameterMapping.Builder(config, "bio", registry.getTypeHandler(String.class))
212             .jdbcType(JdbcType.VARCHAR).build());
213         add(new ParameterMapping.Builder(config, "favouriteSection", registry.getTypeHandler(Section.class))
214             .jdbcType(JdbcType.VARCHAR).build());
215       }
216     }, parameterObject);
217 
218     DefaultParameterHandler defaultParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject,
219         boundSql);
220 
221     PreparedStatement ps = mock(PreparedStatement.class);
222 
223     defaultParameterHandler.setParameters(ps);
224 
225     verify(ps, times(1)).setInt(1, parameterObject.getId());
226     verify(ps, times(1)).setString(2, parameterObject.getUsername());
227     verify(ps, times(1)).setString(3, parameterObject.getPassword());
228     verify(ps, times(1)).setString(4, parameterObject.getEmail());
229     verify(ps, times(1)).setString(5, parameterObject.getBio());
230     verify(ps, times(1)).setObject(6, parameterObject.getFavouriteSection().name(), JdbcType.VARCHAR.TYPE_CODE);
231   }
232 
233   @Test
234   void testParameterObjectGetPropertyValueWithMetaObjectAndCreateOnce() {
235     Author parameterObject = mock(Author.class);
236 
237     Configuration mockConfig = mock(Configuration.class);
238 
239     final ObjectFactory objectFactory = new DefaultObjectFactory();
240     final ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
241     final ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
242 
243     when(mockConfig.getTypeHandlerRegistry()).thenReturn(new TypeHandlerRegistry(mockConfig));
244     when(mockConfig.getDefaultScriptingLanguageInstance()).thenReturn(new XMLLanguageDriver());
245     when(mockConfig.newMetaObject(parameterObject))
246         .thenReturn(MetaObject.forObject(parameterObject, objectFactory, objectWrapperFactory, reflectorFactory));
247 
248     TypeHandlerRegistry registry = mockConfig.getTypeHandlerRegistry();
249 
250     MappedStatement mappedStatement = new MappedStatement.Builder(mockConfig, "testSelect",
251         new StaticSqlSource(mockConfig, "some select statement"), SqlCommandType.SELECT).build();
252 
253     BoundSql boundSql = new BoundSql(mockConfig, "some select statement", new ArrayList<ParameterMapping>() {
254       {
255         add(new ParameterMapping.Builder(mockConfig, "id", registry.getTypeHandler(int.class))
256             .jdbcType(JdbcType.INTEGER).build());
257         add(new ParameterMapping.Builder(mockConfig, "username", registry.getTypeHandler(String.class))
258             .jdbcType(JdbcType.VARCHAR).build());
259         add(new ParameterMapping.Builder(mockConfig, "password", registry.getTypeHandler(String.class))
260             .jdbcType(JdbcType.VARCHAR).build());
261         add(new ParameterMapping.Builder(mockConfig, "email", registry.getTypeHandler(String.class))
262             .jdbcType(JdbcType.VARCHAR).build());
263         add(new ParameterMapping.Builder(mockConfig, "bio", registry.getTypeHandler(String.class))
264             .jdbcType(JdbcType.VARCHAR).build());
265         add(new ParameterMapping.Builder(mockConfig, "favouriteSection", registry.getTypeHandler(Section.class))
266             .jdbcType(JdbcType.VARCHAR).build());
267       }
268     }, parameterObject);
269 
270     DefaultParameterHandler defaultParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject,
271         boundSql);
272 
273     PreparedStatement ps = mock(PreparedStatement.class);
274 
275     defaultParameterHandler.setParameters(ps);
276 
277     verify(parameterObject, times(1)).getId();
278     verify(parameterObject, times(1)).getUsername();
279     verify(parameterObject, times(1)).getPassword();
280     verify(parameterObject, times(1)).getEmail();
281     verify(parameterObject, times(1)).getBio();
282     verify(parameterObject, times(1)).getFavouriteSection();
283 
284     verify(mockConfig, times(1)).newMetaObject(parameterObject);
285   }
286 }