View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.dbutils;
18  
19  import static org.junit.Assert.assertArrayEquals;
20  
21  import java.beans.Introspector;
22  import java.beans.PropertyDescriptor;
23  import java.sql.ResultSet;
24  import java.sql.ResultSetMetaData;
25  import java.sql.SQLException;
26  import java.util.Arrays;
27  import java.util.HashMap;
28  import java.util.List;
29  import java.util.Map;
30  
31  public class BeanProcessorTest extends BaseTestCase {
32  
33      private static class IndexedPropertyTestClass {
34          private String name;
35          // Indexed variable with indexed getter and setter
36          private List<String> things;
37          // Indexed variable without indexed getter or setter
38          private List<String> stuff;
39  
40          public String getName() {
41              return name;
42          }
43  
44          public List<String> getStuff() {
45              return stuff;
46          }
47  
48          public String getThing(final int idx) {
49              return things.get(idx);
50          }
51  
52          public List<String> getThings() {
53              return things;
54          }
55  
56          public void setName(final String name) {
57              this.name = name;
58          }
59  
60          public void setStuff(final List<String> stuff) {
61              this.stuff = stuff;
62          }
63  
64          public void setThing(final int idx, final String thing) {
65              this.things.set(idx, thing);
66          }
67  
68          public void setThings(final List<String> things) {
69              this.things = things;
70          }
71      }
72  
73      public static class MapColumnToAnnotationFieldBean {
74          private String one;
75  
76          private String two;
77  
78          private String three;
79  
80          private String four;
81  
82          public String getFour() {
83              return four;
84          }
85  
86          public String getOne() {
87              return one;
88          }
89  
90          @Column(name = "three_")
91          public String getThree() {
92              return three;
93          }
94  
95          public String getTwo() {
96              return two;
97          }
98  
99          public void setFour(final String four) {
100             this.four = four;
101         }
102 
103         public void setOne(final String one) {
104             this.one = one;
105         }
106 
107         public void setThree(final String three) {
108             this.three = three;
109         }
110 
111         public void setTwo(final String two) {
112             this.two = two;
113         }
114     }
115 
116     public static class MapColumnToPropertiesBean {
117         private String one;
118 
119         private String two;
120 
121         private String three;
122 
123         private String four;
124 
125         public String getFour() {
126             return four;
127         }
128 
129         public String getOne() {
130             return one;
131         }
132 
133         public String getThree() {
134             return three;
135         }
136 
137         public String getTwo() {
138             return two;
139         }
140 
141         public void setFour(final String four) {
142             this.four = four;
143         }
144 
145         public void setOne(final String one) {
146             this.one = one;
147         }
148 
149         public void setThree(final String three) {
150             this.three = three;
151         }
152 
153         public void setTwo(final String two) {
154             this.two = two;
155         }
156     }
157 
158     private static final class TestNoGetter {
159         public String testField;
160 
161         /**
162          * Add setter to trigger JavaBeans to populate a PropertyDescriptor
163          *
164          * @param testField The new testField value
165          */
166         public void setTestField(final String testField) {
167             this.testField = testField;
168         }
169     }
170 
171     private static final class TestWrongSetter {
172         public Integer testField;
173 
174         public Integer getTestField() {
175             return testField;
176         }
177 
178         /**
179          * dbutils checks for a setter with exactly 1 param. This tests resilience
180          * to a found setter that doesn't match expectations.
181          * @param idx
182          * @param testField
183          */
184         public void setTestField(final int idx, final Integer testField) {
185             this.testField = testField;
186         }
187     }
188 
189     private static final BeanProcessor beanProc = new BeanProcessor();
190 
191     public void testCheckAnnotationOnMissingReadMethod() throws Exception {
192         final String[] colNames = {"testField"};
193         final ResultSetMetaData metaData = MockResultSetMetaData.create(colNames);
194 
195         final String testField = "first";
196         final Object[][] rows = {
197                 new Object[] {testField}
198         };
199 
200         final ResultSet rs = MockResultSet.create(metaData, rows);
201         assertTrue(rs.next());
202         TestNoGetter testCls = new TestNoGetter();
203         testCls = beanProc.populateBean(rs, testCls);
204         assertEquals(testCls.testField, "first");
205     }
206 
207     /**
208      * Based on the report in DBUTILS-150. This test validates that indexed
209      * property descriptors are not used, and indexed getter/setter methods
210      * are not inspected.
211      *
212      * @throws Exception
213      * @see <a href="https://issues.apache.org/jira/browse/DBUTILS-150">DBUTILS-150</a>
214      */
215     public void testIndexedPropertyDescriptor() throws Exception {
216         final String[] colNames = {"name", "things", "stuff"};
217         final ResultSetMetaData metaData = MockResultSetMetaData.create(colNames);
218 
219         final String name = "first";
220         final List<String> things = Arrays.asList("1", "2", "3", "4");
221         final List<String> stuff = things;
222         final Object[][] rows = {
223                 new Object[] {name, things, stuff}
224         };
225 
226         final ResultSet rs = MockResultSet.create(metaData, rows);
227         assertTrue(rs.next());
228         IndexedPropertyTestClass testCls = new IndexedPropertyTestClass();
229         testCls = beanProc.populateBean(rs, testCls);
230         assertEquals(name, testCls.getName());
231         assertArrayEquals(things.toArray(), testCls.getThings().toArray());
232         assertArrayEquals(stuff.toArray(), testCls.getStuff().toArray());
233     }
234 
235     public void testMapColumnToAnnotationField() throws Exception {
236         final String[] columnNames = { "test", "test", "three_" };
237         final String[] columnLabels = { "one", "two", null };
238         final ResultSetMetaData rsmd = ProxyFactory.instance().createResultSetMetaData(
239                 new MockResultSetMetaData(columnNames, columnLabels));
240         final PropertyDescriptor[] props = Introspector.getBeanInfo(MapColumnToAnnotationFieldBean.class).getPropertyDescriptors();
241 
242         final int[] columns = beanProc.mapColumnsToProperties(rsmd, props);
243         for (int i = 1; i < columns.length; i++) {
244             assertTrue(columns[i] != BeanProcessor.PROPERTY_NOT_FOUND);
245         }
246     }
247 
248     public void testMapColumnToProperties() throws Exception {
249         final String[] columnNames = { "test", "test", "three" };
250         final String[] columnLabels = { "one", "two", null };
251         final ResultSetMetaData rsmd = ProxyFactory.instance().createResultSetMetaData(
252                 new MockResultSetMetaData(columnNames, columnLabels));
253         final PropertyDescriptor[] props = Introspector.getBeanInfo(MapColumnToPropertiesBean.class).getPropertyDescriptors();
254 
255         final int[] columns = beanProc.mapColumnsToProperties(rsmd, props);
256         for (int i = 1; i < columns.length; i++) {
257             assertTrue(columns[i] != BeanProcessor.PROPERTY_NOT_FOUND);
258         }
259     }
260 
261     public void testMapColumnToPropertiesWithOverrides() throws Exception {
262         final Map<String, String> columnToPropertyOverrides = new HashMap<>();
263         columnToPropertyOverrides.put("five", "four");
264         final BeanProcessor beanProc = new BeanProcessor(columnToPropertyOverrides);
265         final String[] columnNames = { "test", "test", "three", "five" };
266         final String[] columnLabels = { "one", "two", null, null };
267         final ResultSetMetaData rsmd = ProxyFactory.instance().createResultSetMetaData(
268                 new MockResultSetMetaData(columnNames, columnLabels));
269         final PropertyDescriptor[] props = Introspector.getBeanInfo(MapColumnToPropertiesBean.class).getPropertyDescriptors();
270 
271         final int[] columns = beanProc.mapColumnsToProperties(rsmd, props);
272         for (int i = 1; i < columns.length; i++) {
273             assertTrue(columns[i] != BeanProcessor.PROPERTY_NOT_FOUND);
274         }
275     }
276 
277     public void testProcessWithPopulateBean() throws SQLException {
278         TestBean b = new TestBean();
279 
280         assertTrue(this.rs.next());
281         b = beanProc.populateBean(this.rs, b);
282         assertEquals(13.0, b.getColumnProcessorDoubleTest(), 0);
283         assertEquals(b.getThree(), TestBean.Ordinal.THREE);
284 
285         assertTrue(this.rs.next());
286         b = beanProc.populateBean(this.rs, b);
287         assertEquals(13.0, b.getColumnProcessorDoubleTest(), 0);
288         assertEquals(b.getThree(), TestBean.Ordinal.SIX);
289 
290         assertFalse(this.rs.next());
291     }
292 
293     public void testProcessWithToBean() throws SQLException {
294         assertTrue(this.rs.next());
295         TestBean b = beanProc.toBean(this.rs, TestBean.class);
296         assertEquals(13.0, b.getColumnProcessorDoubleTest(), 0);
297         assertEquals(b.getThree(), TestBean.Ordinal.THREE);
298 
299         assertTrue(this.rs.next());
300         b = beanProc.toBean(this.rs, TestBean.class);
301         assertEquals(13.0, b.getColumnProcessorDoubleTest(), 0);
302         assertEquals(b.getThree(), TestBean.Ordinal.SIX);
303 
304         assertFalse(this.rs.next());
305     }
306 
307     public void testWrongSetterParamCount() throws Exception {
308         final String[] colNames = {"testField"};
309         final ResultSetMetaData metaData = MockResultSetMetaData.create(colNames);
310 
311         final Integer testField = 1;
312         final Object[][] rows = {
313                 new Object[] {testField}
314         };
315 
316         final ResultSet rs = MockResultSet.create(metaData, rows);
317         assertTrue(rs.next());
318         TestWrongSetter testCls = new TestWrongSetter();
319         testCls = beanProc.populateBean(rs, testCls);
320         assertNull(testCls.testField);
321     }
322 }