1 | /* |
2 | * Copyright 2007 brunella ltd |
3 | * |
4 | * Licensed under the LGPL Version 3 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * |
7 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
8 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
11 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
12 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
13 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
14 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
15 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
16 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
17 | * THE POSSIBILITY OF SUCH DAMAGE. |
18 | */ |
19 | package sf.qof.codegen; |
20 | |
21 | import static sf.qof.codegen.Constants.SIG_booleanValue; |
22 | import static sf.qof.codegen.Constants.SIG_byteValue; |
23 | import static sf.qof.codegen.Constants.SIG_doubleValue; |
24 | import static sf.qof.codegen.Constants.SIG_floatValue; |
25 | import static sf.qof.codegen.Constants.SIG_getTimeLong; |
26 | import static sf.qof.codegen.Constants.SIG_intValue; |
27 | import static sf.qof.codegen.Constants.SIG_longValue; |
28 | import static sf.qof.codegen.Constants.SIG_setBoolean; |
29 | import static sf.qof.codegen.Constants.SIG_setByte; |
30 | import static sf.qof.codegen.Constants.SIG_setDate; |
31 | import static sf.qof.codegen.Constants.SIG_setDouble; |
32 | import static sf.qof.codegen.Constants.SIG_setFloat; |
33 | import static sf.qof.codegen.Constants.SIG_setInt; |
34 | import static sf.qof.codegen.Constants.SIG_setLong; |
35 | import static sf.qof.codegen.Constants.SIG_setNull; |
36 | import static sf.qof.codegen.Constants.SIG_setShort; |
37 | import static sf.qof.codegen.Constants.SIG_setString; |
38 | import static sf.qof.codegen.Constants.SIG_setTime; |
39 | import static sf.qof.codegen.Constants.SIG_setTimestamp; |
40 | import static sf.qof.codegen.Constants.SIG_shortValue; |
41 | import static sf.qof.codegen.Constants.TYPE_Boolean; |
42 | import static sf.qof.codegen.Constants.TYPE_Byte; |
43 | import static sf.qof.codegen.Constants.TYPE_Character; |
44 | import static sf.qof.codegen.Constants.TYPE_Date; |
45 | import static sf.qof.codegen.Constants.TYPE_Double; |
46 | import static sf.qof.codegen.Constants.TYPE_Float; |
47 | import static sf.qof.codegen.Constants.TYPE_Integer; |
48 | import static sf.qof.codegen.Constants.TYPE_Long; |
49 | import static sf.qof.codegen.Constants.TYPE_Short; |
50 | import static sf.qof.codegen.Constants.TYPE_String; |
51 | import static sf.qof.codegen.Constants.TYPE_boolean; |
52 | import static sf.qof.codegen.Constants.TYPE_byte; |
53 | import static sf.qof.codegen.Constants.TYPE_char; |
54 | import static sf.qof.codegen.Constants.TYPE_double; |
55 | import static sf.qof.codegen.Constants.TYPE_float; |
56 | import static sf.qof.codegen.Constants.TYPE_int; |
57 | import static sf.qof.codegen.Constants.TYPE_long; |
58 | import static sf.qof.codegen.Constants.TYPE_short; |
59 | import static sf.qof.codegen.Constants.TYPE_sqlDate; |
60 | import static sf.qof.codegen.Constants.TYPE_sqlTime; |
61 | import static sf.qof.codegen.Constants.TYPE_sqlTimestamp; |
62 | |
63 | import java.lang.reflect.Method; |
64 | |
65 | import net.sf.cglib.core.CodeEmitter; |
66 | import net.sf.cglib.core.Local; |
67 | import net.sf.cglib.core.Signature; |
68 | |
69 | import org.objectweb.asm.Label; |
70 | import org.objectweb.asm.Type; |
71 | |
72 | import sf.qof.adapter.DynamicMappingAdapter; |
73 | import sf.qof.adapter.GeneratorMappingAdapter; |
74 | import sf.qof.mapping.AbstractCharacterMapping; |
75 | import sf.qof.mapping.AbstractDateTimeMapping; |
76 | import sf.qof.mapping.AbstractNumberMapping; |
77 | import sf.qof.mapping.AdapterMapping; |
78 | import sf.qof.mapping.CharacterMappingVisitor; |
79 | import sf.qof.mapping.DateTimeMappingVisitor; |
80 | import sf.qof.mapping.Mapper; |
81 | import sf.qof.mapping.MappingVisitor; |
82 | import sf.qof.mapping.MethodParameterInfo; |
83 | import sf.qof.mapping.NumberMappingVisitor; |
84 | import sf.qof.mapping.ParameterMapping; |
85 | import sf.qof.mapping.AbstractCharacterMapping.CharacterMapping; |
86 | import sf.qof.mapping.AbstractCharacterMapping.StringMapping; |
87 | import sf.qof.mapping.AbstractDateTimeMapping.DateMapping; |
88 | import sf.qof.mapping.AbstractDateTimeMapping.TimeMapping; |
89 | import sf.qof.mapping.AbstractDateTimeMapping.TimestampMapping; |
90 | import sf.qof.mapping.AbstractNumberMapping.BooleanMapping; |
91 | import sf.qof.mapping.AbstractNumberMapping.ByteMapping; |
92 | import sf.qof.mapping.AbstractNumberMapping.DoubleMapping; |
93 | import sf.qof.mapping.AbstractNumberMapping.FloatMapping; |
94 | import sf.qof.mapping.AbstractNumberMapping.IntegerMapping; |
95 | import sf.qof.mapping.AbstractNumberMapping.LongMapping; |
96 | import sf.qof.mapping.AbstractNumberMapping.ShortMapping; |
97 | import sf.qof.util.ReflectionUtils; |
98 | |
99 | /** |
100 | * Internal - ParameterMappingGenerator is the generator class for parameter mappings. |
101 | */ |
102 | public class ParameterMappingGenerator implements MappingVisitor, NumberMappingVisitor, CharacterMappingVisitor, |
103 | DateTimeMappingVisitor { |
104 | |
105 | private CodeEmitter co; |
106 | private Local preparedStatement; |
107 | private Local[] currentCollectionObj; |
108 | private int[] collectionIndexes; |
109 | private Local parameterIndexOffset; |
110 | |
111 | public ParameterMappingGenerator(CodeEmitter co, Local statement, Local[] currentCollectionObjs, |
112 | MethodParameterInfo[] parameterInfos, Local parameterIndexOffset) { |
113 | this.co = co; |
114 | this.preparedStatement = statement; |
115 | this.currentCollectionObj = currentCollectionObjs; |
116 | this.parameterIndexOffset = parameterIndexOffset; |
117 | if (parameterInfos != null) { |
118 | collectionIndexes = new int[parameterInfos.length]; |
119 | for (int i = 0; i < parameterInfos.length; i++) { |
120 | collectionIndexes[i] = parameterInfos[i].getIndex(); |
121 | } |
122 | } |
123 | } |
124 | |
125 | private void loadValue(int argIndex, Method getter, boolean usesCollection) { |
126 | // if (currentCollectionObj == null) { |
127 | if (!usesCollection) { |
128 | // load value from a method parameter |
129 | co.load_arg(argIndex); |
130 | } else { |
131 | // load value from the current object of the iterator |
132 | co.load_local(currentCollectionObj[findIndex(argIndex)]); |
133 | // co.checkcast(Type.getType(getter.getDeclaringClass())); |
134 | } |
135 | // invoke the getter |
136 | if (getter != null) { |
137 | co.invoke_virtual(Type.getType(getter.getDeclaringClass()), ReflectionUtils.getMethodSignature(getter)); |
138 | } |
139 | } |
140 | |
141 | private int findIndex(int argIndex) { |
142 | for (int i = 0; i < collectionIndexes.length; i++) { |
143 | if (collectionIndexes[i] == argIndex) { |
144 | return i; |
145 | } |
146 | } |
147 | throw new RuntimeException("Inconsistent state"); |
148 | } |
149 | |
150 | // implementation of MappingVisitor |
151 | |
152 | public final void visit(Mapper mapper, AbstractNumberMapping mapping) { |
153 | mapping.accept(mapper, (NumberMappingVisitor) this); |
154 | } |
155 | |
156 | public final void visit(Mapper mapper, AbstractCharacterMapping mapping) { |
157 | mapping.accept(mapper, (CharacterMappingVisitor) this); |
158 | } |
159 | |
160 | public final void visit(Mapper mapper, AbstractDateTimeMapping mapping) { |
161 | mapping.accept(mapper, (DateTimeMappingVisitor) this); |
162 | } |
163 | |
164 | // implementation of NumberMappingVisitor |
165 | |
166 | public void visit(Mapper mapper, ByteMapping mapping) { |
167 | generateParameterMapping(mapping, TYPE_Byte, TYPE_byte, SIG_byteValue, SIG_setByte, java.sql.Types.TINYINT); |
168 | } |
169 | |
170 | public void visit(Mapper mapper, ShortMapping mapping) { |
171 | generateParameterMapping(mapping, TYPE_Short, TYPE_short, SIG_shortValue, SIG_setShort, java.sql.Types.SMALLINT); |
172 | } |
173 | |
174 | public void visit(Mapper mapper, IntegerMapping mapping) { |
175 | generateParameterMapping(mapping, TYPE_Integer, TYPE_int, SIG_intValue, SIG_setInt, java.sql.Types.INTEGER); |
176 | } |
177 | |
178 | public void visit(Mapper mapper, LongMapping mapping) { |
179 | generateParameterMapping(mapping, TYPE_Long, TYPE_long, SIG_longValue, SIG_setLong, java.sql.Types.BIGINT); |
180 | } |
181 | |
182 | public void visit(Mapper mapper, FloatMapping mapping) { |
183 | generateParameterMapping(mapping, TYPE_Float, TYPE_float, SIG_floatValue, SIG_setFloat, java.sql.Types.REAL); |
184 | } |
185 | |
186 | public void visit(Mapper mapper, DoubleMapping mapping) { |
187 | generateParameterMapping(mapping, TYPE_Double, TYPE_double, SIG_doubleValue, SIG_setDouble, java.sql.Types.DOUBLE); |
188 | } |
189 | |
190 | public void visit(Mapper mapper, BooleanMapping mapping) { |
191 | generateParameterMapping(mapping, TYPE_Boolean, TYPE_boolean, SIG_booleanValue, SIG_setBoolean, java.sql.Types.BOOLEAN); |
192 | } |
193 | |
194 | private void generateParameterMapping(ParameterMapping mapping, Type boxedType, Type unboxedType, |
195 | Signature signatureUnbox, Signature signatureSet, int sqlType) { |
196 | int argIndex = mapping.getIndex(); |
197 | int sqlIndex = mapping.getSqlIndexes()[0]; |
198 | Method getter = mapping.getGetter(); |
199 | Class<?> objectType = mapping.getType(); |
200 | |
201 | if (mapping.usesArray()) { |
202 | Local localIndex = co.make_local(TYPE_int); |
203 | co.push(0); |
204 | co.store_local(localIndex); |
205 | Label labelLoopTest = co.make_label(); |
206 | co.goTo(labelLoopTest); |
207 | Label labelLoopStart = co.make_label(); |
208 | co.mark(labelLoopStart); |
209 | |
210 | co.load_local(preparedStatement); |
211 | co.push(sqlIndex); |
212 | co.load_local(parameterIndexOffset); |
213 | co.math(CodeEmitter.ADD, TYPE_int); |
214 | co.load_arg(argIndex); |
215 | co.load_local(localIndex); |
216 | if (objectType.isPrimitive()) { |
217 | co.array_load(unboxedType); |
218 | } else { |
219 | // should we check null values? |
220 | co.array_load(boxedType); |
221 | co.invoke_virtual(boxedType, signatureUnbox); |
222 | } |
223 | |
224 | co.invoke_interface(preparedStatement.getType(), signatureSet); |
225 | |
226 | co.iinc(parameterIndexOffset, 1); |
227 | |
228 | co.iinc(localIndex, 1); |
229 | co.mark(labelLoopTest); |
230 | co.load_local(localIndex); |
231 | co.load_arg(argIndex); |
232 | co.arraylength(); |
233 | co.if_icmp(CodeEmitter.LT, labelLoopStart); |
234 | |
235 | co.iinc(parameterIndexOffset, -1); |
236 | |
237 | } else { |
238 | |
239 | if (!objectType.isPrimitive()) { |
240 | // it's an Integer |
241 | Label lIsNull = co.make_label(); |
242 | Label lEnd = co.make_label(); |
243 | // if (value != null) ps.setInt(index, value.intValue); |
244 | loadValue(argIndex, getter, mapping.usesCollection()); |
245 | co.ifnull(lIsNull); |
246 | co.load_local(preparedStatement); |
247 | co.push(sqlIndex); |
248 | if (parameterIndexOffset != null) { |
249 | co.load_local(parameterIndexOffset); |
250 | co.math(CodeEmitter.ADD, TYPE_int); |
251 | } |
252 | loadValue(argIndex, getter, mapping.usesCollection()); |
253 | co.invoke_virtual(boxedType, signatureUnbox); |
254 | co.invoke_interface(preparedStatement.getType(), signatureSet); |
255 | co.goTo(lEnd); |
256 | // else ps.setNull(index, java.sql.Type.NUMERIC); |
257 | co.mark(lIsNull); |
258 | co.load_local(preparedStatement); |
259 | co.push(sqlIndex); |
260 | // co.push(java.sql.Types.NUMERIC); |
261 | co.push(sqlType); |
262 | co.invoke_interface(preparedStatement.getType(), SIG_setNull); |
263 | |
264 | co.mark(lEnd); |
265 | |
266 | } else { |
267 | // it's an int |
268 | // setInt(index, value); |
269 | co.load_local(preparedStatement); |
270 | co.push(sqlIndex); |
271 | if (parameterIndexOffset != null) { |
272 | co.load_local(parameterIndexOffset); |
273 | co.math(CodeEmitter.ADD, TYPE_int); |
274 | } |
275 | loadValue(argIndex, getter, mapping.usesCollection()); |
276 | co.invoke_interface(preparedStatement.getType(), signatureSet); |
277 | } |
278 | } |
279 | } |
280 | |
281 | // implementation of CharacterMappingVisitor |
282 | |
283 | public final void visit(Mapper mapper, StringMapping mapping) { |
284 | int argIndex = mapping.getIndex(); |
285 | int sqlIndex = mapping.getSqlIndexes()[0]; |
286 | Method getter = mapping.getGetter(); |
287 | |
288 | if (mapping.usesArray()) { |
289 | Local localIndex = co.make_local(TYPE_int); |
290 | co.push(0); |
291 | co.store_local(localIndex); |
292 | Label labelLoopTest = co.make_label(); |
293 | co.goTo(labelLoopTest); |
294 | Label labelLoopStart = co.make_label(); |
295 | co.mark(labelLoopStart); |
296 | |
297 | co.load_local(preparedStatement); |
298 | co.push(sqlIndex); |
299 | co.load_local(parameterIndexOffset); |
300 | co.math(CodeEmitter.ADD, TYPE_int); |
301 | co.load_arg(argIndex); |
302 | co.load_local(localIndex); |
303 | co.array_load(TYPE_String); |
304 | |
305 | co.invoke_interface(preparedStatement.getType(), SIG_setString); |
306 | |
307 | co.iinc(parameterIndexOffset, 1); |
308 | |
309 | co.iinc(localIndex, 1); |
310 | co.mark(labelLoopTest); |
311 | co.load_local(localIndex); |
312 | co.load_arg(argIndex); |
313 | co.arraylength(); |
314 | co.if_icmp(CodeEmitter.LT, labelLoopStart); |
315 | |
316 | co.iinc(parameterIndexOffset, -1); |
317 | |
318 | } else { |
319 | // setString(index, value); |
320 | co.load_local(preparedStatement); |
321 | co.push(sqlIndex); |
322 | if (parameterIndexOffset != null) { |
323 | co.load_local(parameterIndexOffset); |
324 | co.math(CodeEmitter.ADD, TYPE_int); |
325 | } |
326 | loadValue(argIndex, getter, mapping.usesCollection()); |
327 | co.invoke_interface(preparedStatement.getType(), SIG_setString); |
328 | } |
329 | } |
330 | |
331 | public final void visit(Mapper mapper, CharacterMapping mapping) { |
332 | int argIndex = mapping.getIndex(); |
333 | int sqlIndex = mapping.getSqlIndexes()[0]; |
334 | Method getter = mapping.getGetter(); |
335 | Class<?> objectType = mapping.getType(); |
336 | |
337 | if (mapping.usesArray()) { |
338 | Local localIndex = co.make_local(TYPE_int); |
339 | co.push(0); |
340 | co.store_local(localIndex); |
341 | Label labelLoopTest = co.make_label(); |
342 | co.goTo(labelLoopTest); |
343 | Label labelLoopStart = co.make_label(); |
344 | co.mark(labelLoopStart); |
345 | |
346 | co.load_local(preparedStatement); |
347 | co.push(sqlIndex); |
348 | co.load_local(parameterIndexOffset); |
349 | co.math(CodeEmitter.ADD, TYPE_int); |
350 | co.load_arg(argIndex); |
351 | co.load_local(localIndex); |
352 | |
353 | if (objectType.isPrimitive()) { |
354 | // it's a char |
355 | // Character.toString(char) |
356 | co.array_load(TYPE_char); |
357 | co.invoke_static(TYPE_Character, new Signature("toString", "(C)Ljava/lang/String;")); |
358 | } else { |
359 | // it's a Character |
360 | co.array_load(TYPE_Character); |
361 | co.dup(); |
362 | Label labelEnd = co.make_label(); |
363 | Label labelNull = co.make_label(); |
364 | co.ifnull(labelNull); |
365 | co.invoke_virtual(TYPE_Character, new Signature("toString", "()Ljava/lang/String;")); |
366 | co.goTo(labelEnd); |
367 | co.mark(labelNull); |
368 | co.pop(); |
369 | co.aconst_null(); |
370 | co.mark(labelEnd); |
371 | } |
372 | co.invoke_interface(preparedStatement.getType(), SIG_setString); |
373 | |
374 | co.iinc(parameterIndexOffset, 1); |
375 | |
376 | co.iinc(localIndex, 1); |
377 | co.mark(labelLoopTest); |
378 | co.load_local(localIndex); |
379 | co.load_arg(argIndex); |
380 | co.arraylength(); |
381 | co.if_icmp(CodeEmitter.LT, labelLoopStart); |
382 | |
383 | co.iinc(parameterIndexOffset, -1); |
384 | |
385 | } else { |
386 | // setString(index, value); |
387 | co.load_local(preparedStatement); |
388 | co.push(sqlIndex); |
389 | if (parameterIndexOffset != null) { |
390 | co.load_local(parameterIndexOffset); |
391 | co.math(CodeEmitter.ADD, TYPE_int); |
392 | } |
393 | if (objectType.isPrimitive()) { |
394 | // it's a char |
395 | // Character.toString(char) |
396 | loadValue(argIndex, getter, mapping.usesCollection()); |
397 | co.invoke_static(TYPE_Character, new Signature("toString", "(C)Ljava/lang/String;")); |
398 | } else { |
399 | // it's a Character |
400 | loadValue(argIndex, getter, mapping.usesCollection()); |
401 | co.dup(); |
402 | Label labelEnd = co.make_label(); |
403 | Label labelNull = co.make_label(); |
404 | co.ifnull(labelNull); |
405 | co.invoke_virtual(TYPE_Character, new Signature("toString", "()Ljava/lang/String;")); |
406 | co.goTo(labelEnd); |
407 | co.mark(labelNull); |
408 | co.pop(); |
409 | co.aconst_null(); |
410 | co.mark(labelEnd); |
411 | } |
412 | co.invoke_interface(preparedStatement.getType(), SIG_setString); |
413 | } |
414 | } |
415 | |
416 | // implementation of DateTimeVisitor |
417 | |
418 | public void visit(Mapper mapper, DateMapping mapping) { |
419 | generateParameterMapping(mapping, TYPE_sqlDate, SIG_setDate, java.sql.Types.DATE); |
420 | } |
421 | |
422 | public void visit(Mapper mapper, TimeMapping mapping) { |
423 | generateParameterMapping(mapping, TYPE_sqlTime, SIG_setTime, java.sql.Types.TIME); |
424 | } |
425 | |
426 | public void visit(Mapper mapper, TimestampMapping mapping) { |
427 | generateParameterMapping(mapping, TYPE_sqlTimestamp, SIG_setTimestamp, java.sql.Types.TIMESTAMP); |
428 | } |
429 | |
430 | public final void generateParameterMapping(AbstractDateTimeMapping mapping, Type sqlType, Signature sqlTypeSet, |
431 | int sqlTypeCode) { |
432 | int argIndex = mapping.getIndex(); |
433 | int sqlIndex = mapping.getSqlIndexes()[0]; |
434 | Method getter = mapping.getGetter(); |
435 | |
436 | if (mapping.usesArray()) { |
437 | Local localIndex = co.make_local(TYPE_int); |
438 | co.push(0); |
439 | co.store_local(localIndex); |
440 | Label labelLoopTest = co.make_label(); |
441 | co.goTo(labelLoopTest); |
442 | Label labelLoopStart = co.make_label(); |
443 | co.mark(labelLoopStart); |
444 | |
445 | co.load_local(preparedStatement); |
446 | co.push(sqlIndex); |
447 | co.load_local(parameterIndexOffset); |
448 | co.math(CodeEmitter.ADD, TYPE_int); |
449 | |
450 | co.new_instance(sqlType); |
451 | co.dup(); |
452 | |
453 | co.load_arg(argIndex); |
454 | co.load_local(localIndex); |
455 | co.aaload(); |
456 | |
457 | co.invoke_virtual(TYPE_Date, SIG_getTimeLong); |
458 | co.invoke_constructor(sqlType, new Signature("<init>", "(J)V")); |
459 | co.invoke_interface(preparedStatement.getType(), sqlTypeSet); |
460 | |
461 | co.iinc(parameterIndexOffset, 1); |
462 | |
463 | co.iinc(localIndex, 1); |
464 | co.mark(labelLoopTest); |
465 | co.load_local(localIndex); |
466 | co.load_arg(argIndex); |
467 | co.arraylength(); |
468 | co.if_icmp(CodeEmitter.LT, labelLoopStart); |
469 | |
470 | co.iinc(parameterIndexOffset, -1); |
471 | |
472 | } else { |
473 | |
474 | Label lIsNull = co.make_label(); |
475 | Label lEnd = co.make_label(); |
476 | // if (value != null) setDate(index, new java.sql.Date(value.getTime())); |
477 | loadValue(argIndex, getter, mapping.usesCollection()); |
478 | co.ifnull(lIsNull); |
479 | co.load_local(preparedStatement); |
480 | co.push(sqlIndex); |
481 | if (parameterIndexOffset != null) { |
482 | co.load_local(parameterIndexOffset); |
483 | co.math(CodeEmitter.ADD, TYPE_int); |
484 | } |
485 | co.new_instance(sqlType); |
486 | co.dup(); |
487 | loadValue(argIndex, getter, mapping.usesCollection()); |
488 | co.invoke_virtual(TYPE_Date, SIG_getTimeLong); |
489 | co.invoke_constructor(sqlType, new Signature("<init>", "(J)V")); |
490 | co.invoke_interface(preparedStatement.getType(), sqlTypeSet); |
491 | co.goTo(lEnd); |
492 | // else ps.setNull(index, java.sql.Type.DATE); |
493 | co.mark(lIsNull); |
494 | co.load_local(preparedStatement); |
495 | co.push(sqlIndex); |
496 | if (parameterIndexOffset != null) { |
497 | co.load_local(parameterIndexOffset); |
498 | co.math(CodeEmitter.ADD, TYPE_int); |
499 | } |
500 | co.push(sqlTypeCode); |
501 | co.invoke_interface(preparedStatement.getType(), SIG_setNull); |
502 | |
503 | co.mark(lEnd); |
504 | } |
505 | } |
506 | |
507 | public final void visit(Mapper mapper, AdapterMapping mapping) { |
508 | int argIndex = mapping.getIndex(); |
509 | int[] sqlIndexes = mapping.getSqlIndexes(); |
510 | Method getter = mapping.getGetter(); |
511 | |
512 | if (mapping.usesArray()) { |
513 | if (mapping.getAdapter().getNumberOfColumns() != 1) { |
514 | throw new RuntimeException("Only adapters for one column can be used for in-clauses"); |
515 | } |
516 | |
517 | Local localIndex = co.make_local(TYPE_int); |
518 | co.push(0); |
519 | co.store_local(localIndex); |
520 | Label labelLoopTest = co.make_label(); |
521 | co.goTo(labelLoopTest); |
522 | Label labelLoopStart = co.make_label(); |
523 | co.mark(labelLoopStart); |
524 | |
525 | if (mapping.getAdapter() instanceof GeneratorMappingAdapter) { |
526 | // load the argument on top of the stack |
527 | co.load_arg(argIndex); |
528 | co.load_local(localIndex); |
529 | co.aaload(); |
530 | ((GeneratorMappingAdapter) mapping.getAdapter()).generateToPreparedStatement( |
531 | mapping, co, preparedStatement, sqlIndexes, parameterIndexOffset); |
532 | } else if (mapping.getAdapter() instanceof DynamicMappingAdapter) { |
533 | co.getfield(QueryObjectGenerator.getAdapterFieldName(mapping.getAdapter().getClass())); |
534 | // set(PreparedStatement ps, Object value, int[] indexes) |
535 | co.load_local(preparedStatement); |
536 | co.load_arg(argIndex); |
537 | co.load_local(localIndex); |
538 | co.aaload(); |
539 | // new int[] {...} |
540 | co.push(sqlIndexes.length); |
541 | co.newarray(TYPE_int); |
542 | for (int i = 0; i < sqlIndexes.length; i++) { |
543 | co.dup(); |
544 | co.push(i); |
545 | co.push(sqlIndexes[i]); |
546 | if (parameterIndexOffset != null) { |
547 | co.load_local(parameterIndexOffset); |
548 | co.math(CodeEmitter.ADD, TYPE_int); |
549 | } |
550 | co.array_store(TYPE_int); |
551 | } |
552 | co.invoke_interface(Type.getType(DynamicMappingAdapter.class), |
553 | new Signature("set", "(Ljava/sql/PreparedStatement;Ljava/lang/Object;[I)V")); |
554 | } else { |
555 | throw new RuntimeException("Unsupported adapter type " + mapping.getAdapter()); |
556 | } |
557 | |
558 | co.iinc(parameterIndexOffset, 1); |
559 | |
560 | co.iinc(localIndex, 1); |
561 | co.mark(labelLoopTest); |
562 | co.load_local(localIndex); |
563 | co.load_arg(argIndex); |
564 | co.arraylength(); |
565 | co.if_icmp(CodeEmitter.LT, labelLoopStart); |
566 | |
567 | co.iinc(parameterIndexOffset, -1); |
568 | |
569 | } else { |
570 | if (mapping.getAdapter() instanceof GeneratorMappingAdapter) { |
571 | loadValue(argIndex, getter, mapping.usesCollection()); |
572 | ((GeneratorMappingAdapter) mapping.getAdapter()).generateToPreparedStatement( |
573 | mapping, co, preparedStatement, sqlIndexes, parameterIndexOffset); |
574 | |
575 | } else if (mapping.getAdapter() instanceof DynamicMappingAdapter) { |
576 | co.getfield(QueryObjectGenerator.getAdapterFieldName(mapping.getAdapter().getClass())); |
577 | // set(PreparedStatement ps, Object value, int[] indexes) |
578 | co.load_local(preparedStatement); |
579 | loadValue(argIndex, getter, mapping.usesCollection()); |
580 | // new int[] {...} |
581 | co.push(sqlIndexes.length); |
582 | co.newarray(TYPE_int); |
583 | for (int i = 0; i < sqlIndexes.length; i++) { |
584 | co.dup(); |
585 | co.push(i); |
586 | co.push(sqlIndexes[i]); |
587 | if (parameterIndexOffset != null) { |
588 | co.load_local(parameterIndexOffset); |
589 | co.math(CodeEmitter.ADD, TYPE_int); |
590 | } |
591 | co.array_store(TYPE_int); |
592 | } |
593 | co.invoke_interface(Type.getType(DynamicMappingAdapter.class), |
594 | new Signature("set", "(Ljava/sql/PreparedStatement;Ljava/lang/Object;[I)V")); |
595 | } else { |
596 | throw new RuntimeException("Unsupported adapter type " + mapping.getAdapter()); |
597 | } |
598 | } |
599 | } |
600 | |
601 | } |