View Javadoc
1   /*
2    *    Copyright 2009-2021 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    *       http://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.submitted.member_access;
17  
18  import static org.junit.jupiter.api.Assertions.*;
19  
20  import java.io.Reader;
21  import java.util.HashMap;
22  import java.util.Map;
23  
24  import org.apache.ibatis.annotations.Arg;
25  import org.apache.ibatis.annotations.ConstructorArgs;
26  import org.apache.ibatis.annotations.Result;
27  import org.apache.ibatis.annotations.Results;
28  import org.apache.ibatis.annotations.Select;
29  import org.apache.ibatis.io.Resources;
30  import org.apache.ibatis.session.SqlSession;
31  import org.apache.ibatis.session.SqlSessionFactory;
32  import org.apache.ibatis.session.SqlSessionFactoryBuilder;
33  import org.junit.jupiter.api.BeforeAll;
34  import org.junit.jupiter.api.Test;
35  
36  /**
37   * Tests for member access of Java Object.
38   */
39  class MemberAccessTest {
40  
41    private static SqlSessionFactory sqlSessionFactory;
42  
43    @BeforeAll
44    static void setUp() throws Exception {
45      try (
46          Reader reader = Resources.getResourceAsReader("org/apache/ibatis/submitted/member_access/mybatis-config.xml")) {
47        sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
48        sqlSessionFactory.getConfiguration().addMapper(Mapper.class);
49      }
50    }
51  
52    @Test
53    void parameterMappingAndResultAutoMapping() {
54      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
55        Mapper mapper = sqlSession.getMapper(Mapper.class);
56  
57        Params params = new Params();
58        Bean bean = mapper.resultAutoMapping(params);
59  
60        assertEquals(params.privateField, bean.privateField);
61        assertEquals(params.packagePrivateField, bean.packagePrivateField);
62        assertEquals(params.protectedField, bean.protectedField);
63        assertEquals(params.publicField, bean.publicField);
64        assertEquals(params.getPrivateProperty(), bean.properties.get("privateProperty"));
65        assertEquals(params.getPackagePrivateProperty(), bean.properties.get("packagePrivateProperty"));
66        assertEquals(params.getProtectedProperty(), bean.properties.get("protectedProperty"));
67        assertEquals(params.getPublicProperty(), bean.properties.get("publicProperty"));
68      }
69    }
70  
71    @Test // gh-1258
72    void parameterMappingAndResultAutoMappingUsingOgnl() {
73      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
74        Mapper mapper = sqlSession.getMapper(Mapper.class);
75  
76        Params params = new Params();
77        Bean bean = mapper.resultAutoMappingUsingOgnl(params);
78  
79        assertEquals(params.privateField + "%", bean.privateField);
80        assertEquals(params.packagePrivateField + "%", bean.packagePrivateField);
81        assertEquals(params.protectedField + "%", bean.protectedField);
82        assertEquals(params.publicField + "%", bean.publicField);
83        assertEquals(params.getPrivateProperty() + "%", bean.properties.get("privateProperty"));
84        assertEquals(params.getPackagePrivateProperty() + "%", bean.properties.get("packagePrivateProperty"));
85        assertEquals(params.getProtectedProperty() + "%", bean.properties.get("protectedProperty"));
86        assertEquals(params.getPublicProperty() + "%", bean.properties.get("publicProperty"));
87      }
88    }
89  
90    @Test
91    void parameterMappingAndResultMapping() {
92      try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
93        Mapper mapper = sqlSession.getMapper(Mapper.class);
94  
95        Params params = new Params();
96        Bean bean = mapper.resultMapping(params);
97  
98        assertEquals(params.privateField, bean.privateField);
99        assertEquals(params.packagePrivateField, bean.packagePrivateField);
100       assertEquals(params.protectedField, bean.protectedField);
101       assertEquals(params.publicField, bean.publicField);
102       assertEquals(params.getPrivateProperty(), bean.properties.get("privateProperty"));
103       assertEquals(params.getPackagePrivateProperty(), bean.properties.get("packagePrivateProperty"));
104       assertEquals(params.getProtectedProperty(), bean.properties.get("protectedProperty"));
105       assertEquals(params.getPublicProperty(), bean.properties.get("publicProperty"));
106     }
107   }
108 
109   @Test
110   void constructorAutoMapping() {
111     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
112       Mapper mapper = sqlSession.getMapper(Mapper.class);
113 
114       {
115         Immutable immutable = mapper.privateConstructorAutoMapping();
116         assertEquals(1, immutable.properties.size());
117         assertEquals("1", immutable.properties.get("arg1"));
118       }
119 
120       {
121         Immutable immutable = mapper.packagePrivateConstructorAutoMapping();
122         assertEquals(2, immutable.properties.size());
123         assertEquals("1", immutable.properties.get("arg1"));
124         assertEquals("2", immutable.properties.get("arg2"));
125       }
126 
127       {
128         Immutable immutable = mapper.protectedConstructorAutoMapping();
129         assertEquals(3, immutable.properties.size());
130         assertEquals("1", immutable.properties.get("arg1"));
131         assertEquals("2", immutable.properties.get("arg2"));
132         assertEquals("3", immutable.properties.get("arg3"));
133       }
134 
135       {
136         Immutable immutable = mapper.publicConstructorAutoMapping();
137         assertEquals(4, immutable.properties.size());
138         assertEquals("1", immutable.properties.get("arg1"));
139         assertEquals("2", immutable.properties.get("arg2"));
140         assertEquals("3", immutable.properties.get("arg3"));
141         assertEquals("4", immutable.properties.get("arg4"));
142       }
143     }
144 
145   }
146 
147   @Test
148   void constructorMapping() {
149     try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
150       Mapper mapper = sqlSession.getMapper(Mapper.class);
151 
152       {
153         Immutable immutable = mapper.privateConstructorMapping();
154         assertEquals(1, immutable.properties.size());
155         assertEquals("1", immutable.properties.get("arg1"));
156       }
157 
158       {
159         Immutable immutable = mapper.packagePrivateConstructorMapping();
160         assertEquals(2, immutable.properties.size());
161         assertEquals("1", immutable.properties.get("arg1"));
162         assertEquals("2", immutable.properties.get("arg2"));
163       }
164 
165       {
166         Immutable immutable = mapper.protectedConstructorMapping();
167         assertEquals(3, immutable.properties.size());
168         assertEquals("1", immutable.properties.get("arg1"));
169         assertEquals("2", immutable.properties.get("arg2"));
170         assertEquals("3", immutable.properties.get("arg3"));
171       }
172 
173       {
174         Immutable immutable = mapper.publicConstructorMapping();
175         assertEquals(4, immutable.properties.size());
176         assertEquals("1", immutable.properties.get("arg1"));
177         assertEquals("2", immutable.properties.get("arg2"));
178         assertEquals("3", immutable.properties.get("arg3"));
179         assertEquals("4", immutable.properties.get("arg4"));
180       }
181     }
182 
183   }
184 
185   interface Mapper {
186     @Select({
187         // @formatter:off
188         "SELECT"
189           ,"#{privateField} as privateField"
190           ,",#{packagePrivateField} as packagePrivateField"
191           ,",#{protectedField} as protectedField"
192           ,",#{publicField} as publicField"
193           ,",#{privateProperty} as privateProperty"
194           ,",#{packagePrivateProperty} as packagePrivateProperty"
195           ,",#{protectedProperty} as protectedProperty"
196           ,",#{publicProperty} as publicProperty"
197         ,"FROM"
198           ,"INFORMATION_SCHEMA.SYSTEM_USERS"
199         // @formatter:on
200     })
201     Bean resultAutoMapping(Params params);
202 
203     @Select({
204         // @formatter:off
205         "<script>"
206 
207           ,"<bind name=\"privateFieldValue\" value=\"_parameter.privateField + '%'\" />"
208           ,"<bind name=\"packagePrivateFieldValue\" value=\"_parameter.packagePrivateField + '%'\" />"
209           ,"<bind name=\"protectedFieldValue\" value=\"_parameter.protectedField + '%'\" />"
210           ,"<bind name=\"publicFieldValue\" value=\"_parameter.publicField + '%'\" />"
211           ,"<bind name=\"privatePropertyValue\" value=\"_parameter.privateProperty + '%'\" />"
212           ,"<bind name=\"packagePrivatePropertyValue\" value=\"_parameter.packagePrivateProperty + '%'\" />"
213           ,"<bind name=\"protectedPropertyValue\" value=\"_parameter.getProtectedProperty() + '%'\" />"
214           ,"<bind name=\"publicPropertyValue\" value=\"_parameter.publicProperty + '%'\" />"
215 
216           ,"SELECT"
217           ,"#{privateFieldValue} as privateField"
218           ,",#{packagePrivateFieldValue} as packagePrivateField"
219           ,",#{protectedFieldValue} as protectedField"
220           ,",#{publicFieldValue} as publicField"
221           ,",#{privatePropertyValue} as privateProperty"
222           ,",#{packagePrivatePropertyValue} as packagePrivateProperty"
223           ,",#{protectedPropertyValue} as protectedProperty"
224           ,",#{publicPropertyValue} as publicProperty"
225 
226           ,"FROM"
227             ,"INFORMATION_SCHEMA.SYSTEM_USERS"
228 
229         ,"</script>"}
230         // @formatter:on
231     )
232     Bean resultAutoMappingUsingOgnl(Params params);
233 
234     @Results({
235         // @formatter:off
236         @Result(property = "privateField", column = "private_field")
237         ,@Result(property = "packagePrivateField", column = "package_private_field")
238         ,@Result(property = "protectedField", column = "protected_field")
239         ,@Result(property = "publicField", column = "public_field")
240         ,@Result(property = "privateProperty", column = "private_property")
241         ,@Result(property = "packagePrivateProperty", column = "package_private_property")
242         ,@Result(property = "protectedProperty", column = "protected_property")
243         ,@Result(property = "publicProperty", column = "public_property")
244         // @formatter:on
245     })
246     @Select({
247         // @formatter:off
248         "SELECT"
249           ,"#{privateField} as private_field"
250           ,",#{packagePrivateField} as package_private_field"
251           ,",#{protectedField} as protected_field"
252           ,",#{publicField} as public_field"
253           ,",#{privateProperty} as private_property"
254           ,",#{packagePrivateProperty} as package_private_property"
255           ,",#{protectedProperty} as protected_property"
256           ,",#{publicProperty} as public_property"
257         ,"FROM"
258           ,"INFORMATION_SCHEMA.SYSTEM_USERS"
259         // @formatter:on
260     })
261     Bean resultMapping(Params params);
262 
263     @Select("SELECT '1' FROM INFORMATION_SCHEMA.SYSTEM_USERS")
264     Immutable privateConstructorAutoMapping();
265 
266     @Select("SELECT '1', '2' FROM INFORMATION_SCHEMA.SYSTEM_USERS")
267     Immutable packagePrivateConstructorAutoMapping();
268 
269     @Select("SELECT '1', '2', '3' FROM INFORMATION_SCHEMA.SYSTEM_USERS")
270     Immutable protectedConstructorAutoMapping();
271 
272     @Select("SELECT '1', '2', '3', '4' FROM INFORMATION_SCHEMA.SYSTEM_USERS")
273     Immutable publicConstructorAutoMapping();
274 
275     @ConstructorArgs({ @Arg(column = "c1", javaType = String.class) })
276     @Select("SELECT '1' as c1 FROM INFORMATION_SCHEMA.SYSTEM_USERS")
277     Immutable privateConstructorMapping();
278 
279     @ConstructorArgs({
280         // @formatter:off
281         @Arg(column = "c1", javaType = String.class)
282         ,@Arg(column = "c2", javaType = String.class)
283         // @formatter:on
284     })
285     @Select("SELECT '1' as c1, '2' as c2 FROM INFORMATION_SCHEMA.SYSTEM_USERS")
286     Immutable packagePrivateConstructorMapping();
287 
288     @ConstructorArgs({
289         // @formatter:off
290         @Arg(column = "c1", javaType = String.class)
291         ,@Arg(column = "c2", javaType = String.class)
292         ,@Arg(column = "c3", javaType = String.class)
293         // @formatter:on
294     })
295     @Select("SELECT '1' as c1, '2' as c2, '3' as c3 FROM INFORMATION_SCHEMA.SYSTEM_USERS")
296     Immutable protectedConstructorMapping();
297 
298     @ConstructorArgs({
299         // @formatter:off
300         @Arg(column = "c1", javaType = String.class)
301         ,@Arg(column = "c2", javaType = String.class)
302         ,@Arg(column = "c3", javaType = String.class)
303         ,@Arg(column = "c4", javaType = String.class)
304         // @formatter:on
305     })
306     @Select("SELECT '1' as c1, '2' as c2, '3' as c3, '4' as c4 FROM INFORMATION_SCHEMA.SYSTEM_USERS")
307     Immutable publicConstructorMapping();
308 
309   }
310 
311   static class Params {
312     private String privateField = "privateField";
313     String packagePrivateField = "packagePrivateField";
314     protected String protectedField = "protectedField";
315     public String publicField = "publicField";
316 
317     private String getPrivateProperty() {
318       return "privateProperty";
319     }
320 
321     String getPackagePrivateProperty() {
322       return "packagePrivateProperty";
323     }
324 
325     protected String getProtectedProperty() {
326       return "protectedProperty";
327     }
328 
329     public String getPublicProperty() {
330       return "publicProperty";
331     }
332   }
333 
334   @SuppressWarnings("unused")
335   static class Bean {
336     private String privateField;
337     String packagePrivateField;
338     protected String protectedField;
339     public String publicField;
340     private Map<String, String> properties = new HashMap<>();
341 
342     private void setPrivateProperty(String value) {
343       properties.put("privateProperty", value);
344     }
345 
346     void setPackagePrivateProperty(String value) {
347       properties.put("packagePrivateProperty", value);
348     }
349 
350     protected void setProtectedProperty(String value) {
351       properties.put("protectedProperty", value);
352     }
353 
354     public void setPublicProperty(String value) {
355       properties.put("publicProperty", value);
356     }
357   }
358 
359   @SuppressWarnings("unused")
360   static class Immutable {
361     private Map<String, String> properties = new HashMap<>();
362 
363     private Immutable(String arg1) {
364       properties.put("arg1", arg1);
365     }
366 
367     Immutable(String arg1, String arg2) {
368       properties.put("arg1", arg1);
369       properties.put("arg2", arg2);
370     }
371 
372     protected Immutable(String arg1, String arg2, String arg3) {
373       properties.put("arg1", arg1);
374       properties.put("arg2", arg2);
375       properties.put("arg3", arg3);
376     }
377 
378     public Immutable(String arg1, String arg2, String arg3, String arg4) {
379       properties.put("arg1", arg1);
380       properties.put("arg2", arg2);
381       properties.put("arg3", arg3);
382       properties.put("arg4", arg4);
383     }
384 
385   }
386 
387 }