1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.dbutils;
18
19 import java.beans.IndexedPropertyDescriptor;
20 import java.beans.PropertyDescriptor;
21 import java.lang.reflect.InvocationHandler;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Proxy;
24 import java.sql.ParameterMetaData;
25 import java.sql.PreparedStatement;
26 import java.sql.SQLException;
27 import java.sql.Types;
28 import java.util.Arrays;
29
30 import junit.framework.TestCase;
31
32 public class QueryRunnerTest extends TestCase {
33 QueryRunner runner;
34 PreparedStatement stmt;
35
36 static final Method getParameterCount, getParameterType, getParameterMetaData;
37 static {
38 try {
39 getParameterCount = ParameterMetaData.class.getMethod("getParameterCount", new Class[0]);
40 getParameterType = ParameterMetaData.class.getMethod("getParameterType", new Class[]{int.class});
41 getParameterMetaData = PreparedStatement.class.getMethod("getParameterMetaData", new Class[0]);
42 } catch (Exception e) {
43 throw new RuntimeException(e);
44 }
45 }
46
47 public void setUp() {
48 runner = new QueryRunner();
49 stmt = fakePreparedStatement();
50 }
51
52 public void testFillStatementWithNull() throws Exception {
53 stmt = fakeFillablePreparedStatement(false, new int[] {Types.VARCHAR, Types.BIGINT});
54 runner.fillStatement(stmt, new Object[] { null, null });
55 }
56
57 public void testFillStatementWithNullOracle() throws Exception {
58 stmt = fakeFillablePreparedStatement(true, new int[] {Types.VARCHAR, Types.BIGINT});
59 runner.fillStatement(stmt, new Object[] { null, null });
60 }
61
62 private PreparedStatement fakeFillablePreparedStatement(final boolean simulateOracle, final int[] types) throws NoSuchMethodException {
63
64 final ParameterMetaData pmd = mockParameterMetaData(simulateOracle,types);
65 InvocationHandler stmtHandler = new InvocationHandler() {
66 public Object invoke(Object proxy, Method method, Object[] args)
67 throws Throwable {
68 if (getParameterMetaData.equals(method)) {
69 return pmd;
70 }
71 return null;
72 }
73 };
74 return ProxyFactory.instance().createPreparedStatement(stmtHandler);
75 }
76
77 private ParameterMetaData mockParameterMetaData(final boolean simulateOracle, final int[] types) {
78 InvocationHandler pmdHandler = new InvocationHandler() {
79 public Object invoke(Object proxy, Method method, Object[] args)
80 throws Throwable {
81 if (getParameterCount.equals(method)) {
82 return new Integer(types.length);
83 }
84 if (getParameterType.equals(method)) {
85 if (simulateOracle) throw new SQLException("Oracle fails when you call getParameterType");
86 int arg = ((Integer)args[0]).intValue();
87 return new Integer(types[arg-1]);
88 }
89 return null;
90 }
91 };
92
93 return (ParameterMetaData) Proxy.newProxyInstance(
94 pmdHandler.getClass().getClassLoader(),
95 new Class[] {ParameterMetaData.class},
96 pmdHandler);
97 }
98
99 public void testFillStatementWithBean() throws SQLException {
100 TestBean tb = new TestBean();
101 tb.setOne("uno");
102 tb.setTwo("dos");
103 tb.setThree("tres");
104 NoOpFillStatement fakeQueryRunner = new NoOpFillStatement();
105 fakeQueryRunner.fillStatementWithBean(stmt, tb, new String[] {"three", "two", "one"});
106 String[] expected = new String[] {"tres", "dos", "uno"};
107 assertArrayEquals("Statement filled with incorrect parameters", expected, fakeQueryRunner.params);
108 }
109
110 private PreparedStatement fakePreparedStatement() {
111 InvocationHandler noOpHandler = new InvocationHandler() {
112 public Object invoke(Object proxy, Method method, Object[] args)
113 throws Throwable {
114 return null;
115 }
116 };
117 PreparedStatement stmt = ProxyFactory.instance().createPreparedStatement(noOpHandler);
118 return stmt;
119 }
120
121 public void testFillStatementWithBeanErrorNoReadMethod() throws Exception {
122 TestBean tb = new TestBean();
123 PropertyDescriptor noReadMethod = new PropertyDescriptor("one", TestBean.class, null, "setOne");
124
125 PropertyDescriptor properties[] = new PropertyDescriptor[] { noReadMethod };
126 try {
127 runner.fillStatementWithBean(stmt, tb, properties);
128 fail("Expected RuntimeException: tried to use a property with no read method");
129 } catch (RuntimeException expected) {}
130 }
131
132 public void testFillStatementWithBeanErrorBadReadMethod() throws Exception {
133 PropertyDescriptor badReadMethod = new IndexedPropertyDescriptor("indexed", getClass(), null, null, "getIndexed", null) {
134 public synchronized Method getReadMethod() {
135 return super.getIndexedReadMethod();
136 }
137 };
138 PropertyDescriptor properties[] = new PropertyDescriptor[] { badReadMethod };
139 try {
140 runner.fillStatementWithBean(stmt, this, properties);
141 fail("Expected RuntimeException: tried to use a property with no no-arg read method");
142 } catch (RuntimeException expected) {}
143 }
144
145 public void testFillStatementWithBeanErrorReadMethodThrows() throws Exception {
146 PropertyDescriptor badReadMethod = new PropertyDescriptor("throwsException", getClass(), "getThrowsException", null);
147 PropertyDescriptor properties[] = new PropertyDescriptor[] { badReadMethod };
148 try {
149 runner.fillStatementWithBean(stmt, this, properties);
150 fail("Expected RuntimeException: tried to call a method that throws");
151 } catch (RuntimeException expected) {}
152 }
153
154 public void testFillStatementWithBeanErrorReadMethodPrivate() throws Exception {
155 getPrivate();
156 PropertyDescriptor badReadMethod = new BadPrivatePropertyDescriptor();
157 PropertyDescriptor properties[] = new PropertyDescriptor[] { badReadMethod };
158 try {
159 runner.fillStatementWithBean(stmt, this, properties);
160 fail("Expected RuntimeException: tried to call a private method");
161 } catch (RuntimeException expected) {}
162 }
163
164 class BadPrivatePropertyDescriptor extends PropertyDescriptor {
165 Method getPrivate;
166 BadPrivatePropertyDescriptor() throws Exception {
167 super("throwsException", QueryRunnerTest.class, "getThrowsException", null);
168 getPrivate = QueryRunnerTest.class.getDeclaredMethod("getPrivate", new Class[0]);
169 }
170
171 public synchronized Method getReadMethod() {
172 if (getPrivate == null) return super.getReadMethod();
173 return getPrivate;
174 }
175 }
176
177 public void testRethrowNullMessage() {
178
179 SQLException sqe = new SQLException((String)null);
180 QueryRunner qr = new QueryRunner();
181 try {
182 qr.rethrow(sqe, "foo", new Object[] {"bar"});
183 fail("rethrow didn't throw");
184 } catch (SQLException expected) {}
185 }
186
187
188 public String getIndexed(int index) {
189 return null;
190 }
191
192 public String getThrowsException() {
193 throw new RuntimeException("this getter always throws an exception");
194 }
195
196 private String getPrivate() {
197 return null;
198 }
199
200 private void assertArrayEquals(String message, Object[] expected, Object[] actual) {
201 assertEquals(message, Arrays.asList(expected).toString(), Arrays.asList(actual).toString());
202 assertEquals(message, expected.length, actual.length);
203 }
204
205
206 private class NoOpFillStatement extends QueryRunner {
207 Object[] params;
208 public void fillStatement(PreparedStatement stmt, Object[] params)
209 throws SQLException {
210 this.params = params;
211 }
212 }
213
214 }