1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package org.codehaus.groovy.runtime;
47
48 import groovy.lang.Binding;
49 import groovy.lang.GroovyObject;
50 import groovy.lang.GroovyRuntimeException;
51 import groovy.lang.IntRange;
52 import groovy.lang.MetaClass;
53 import groovy.lang.ObjectRange;
54 import groovy.lang.Script;
55 import groovy.lang.Tuple;
56 import groovy.lang.Writable;
57
58 import java.io.IOException;
59 import java.io.InputStream;
60 import java.io.InputStreamReader;
61 import java.io.Reader;
62 import java.io.Writer;
63 import java.lang.reflect.Array;
64 import java.math.BigDecimal;
65 import java.math.BigInteger;
66 import java.util.ArrayList;
67 import java.util.Collection;
68 import java.util.HashMap;
69 import java.util.Iterator;
70 import java.util.List;
71 import java.util.Map;
72 import java.util.regex.Matcher;
73 import java.util.regex.Pattern;
74
75 /***
76 * A static helper class to make bytecode generation easier and act as a facade over the Invoker
77 *
78 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
79 * @version $Revision: 1.56 $
80 */
81 public class InvokerHelper {
82 public static final Object[] EMPTY_ARGS = {
83 };
84
85 private static final Object[] EMPTY_MAIN_ARGS = new Object[] { new String[0] };
86
87 private static final Invoker singleton = new Invoker();
88
89 private static final Integer ZERO = new Integer(0);
90 private static final Integer MINUS_ONE = new Integer(-1);
91 private static final Integer ONE = new Integer(1);
92
93 public static MetaClass getMetaClass(Object object) {
94 return getInstance().getMetaClass(object);
95 }
96
97 public static Invoker getInstance() {
98 return singleton;
99 }
100
101 public static Object invokeNoArgumentsMethod(Object object, String methodName) {
102 return getInstance().invokeMethod(object, methodName, EMPTY_ARGS);
103 }
104
105 public static Object invokeMethod(Object object, String methodName, Object arguments) {
106 return getInstance().invokeMethod(object, methodName, arguments);
107 }
108
109 public static Object invokeSuperMethod(Object object, String methodName, Object arguments) {
110 return getInstance().invokeSuperMethod(object, methodName, arguments);
111 }
112
113 public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
114 if (object != null) {
115 return getInstance().invokeMethod(object, methodName, arguments);
116 }
117 return null;
118 }
119
120 public static Object invokeStaticMethod(String type, String methodName, Object arguments) {
121 return getInstance().invokeStaticMethod(type, methodName, arguments);
122 }
123
124 public static Object invokeStaticNoArgumentsMethod(String type, String methodName) {
125 return getInstance().invokeStaticMethod(type, methodName, EMPTY_ARGS);
126 }
127
128 public static Object invokeConstructor(String type, Object arguments) {
129 return getInstance().invokeConstructor(type, arguments);
130 }
131
132 public static Object invokeConstructorOf(Class type, Object arguments) {
133 return getInstance().invokeConstructorOf(type, arguments);
134 }
135
136 public static Object invokeNoArgumentsConstructorOf(Class type) {
137 return getInstance().invokeConstructorOf(type, EMPTY_ARGS);
138 }
139
140 public static Object invokeClosure(Object closure, Object arguments) {
141 return getInstance().invokeMethod(closure, "doCall", arguments);
142 }
143
144 public static Iterator asIterator(Object collection) {
145 return getInstance().asIterator(collection);
146 }
147
148 public static Collection asCollection(Object collection) {
149 return getInstance().asCollection(collection);
150 }
151
152 public static List asList(Object args) {
153 return getInstance().asList(args);
154 }
155
156 public static String toString(Object arguments) {
157 return getInstance().toString(arguments);
158 }
159
160 public static String toTypeString(Object[] arguments) {
161 return getInstance().toTypeString(arguments);
162 }
163
164 public static String inspect(Object self) {
165 return getInstance().inspect(self);
166 }
167
168 public static Object getProperty(Object object, String property) {
169 return getInstance().getProperty(object, property);
170 }
171
172 public static Object getPropertySafe(Object object, String property) {
173 if (object != null) {
174 return getInstance().getProperty(object, property);
175 }
176 return null;
177 }
178
179 public static void setProperty(Object object, String property, Object newValue) {
180 getInstance().setProperty(object, property, newValue);
181 }
182
183 /***
184 * This is so we don't have to reorder the stack when we call this method.
185 * At some point a better name might be in order.
186 */
187 public static void setProperty2(Object newValue, Object object, String property) {
188 getInstance().setProperty(object, property, newValue);
189 }
190
191
192 /***
193 * This is so we don't have to reorder the stack when we call this method.
194 * At some point a better name might be in order.
195 */
196 public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
197 object.setProperty(property, newValue);
198 }
199
200 public static Object getGroovyObjectProperty(GroovyObject object, String property) {
201 return object.getProperty(property);
202 }
203
204
205 /***
206 * This is so we don't have to reorder the stack when we call this method.
207 * At some point a better name might be in order.
208 */
209 public static void setPropertySafe2(Object newValue, Object object, String property) {
210 if (object != null) {
211 setProperty2(newValue, object, property);
212 }
213 }
214
215 /***
216 * Provides a hook for type coercion of the given object to the required type
217 * @param type of object to convert the given object to
218 * @param object the object to be converted
219 * @return the original object or a new converted value
220 */
221 public static Object asType(Object object, Class type) {
222 return getInstance().asType(object, type);
223 }
224
225 public static boolean asBool(Object object) {
226 return getInstance().asBool(object);
227 }
228
229 public static boolean notObject(Object object) {
230 return !asBool(object);
231 }
232
233 public static boolean notBoolean(boolean bool) {
234 return !bool;
235 }
236
237 public static Object negate(Object value) {
238 if (value instanceof Integer) {
239 Integer number = (Integer) value;
240 return integerValue(-number.intValue());
241 }
242 else if (value instanceof Long) {
243 Long number = (Long) value;
244 return new Long(-number.longValue());
245 }
246 else if (value instanceof BigInteger) {
247 return ((BigInteger)value).negate();
248 }
249 else if (value instanceof BigDecimal) {
250 return ((BigDecimal)value).negate();
251 }
252 else if (value instanceof Double) {
253 Double number = (Double) value;
254 return new Double(-number.doubleValue());
255 }
256 else if (value instanceof Float) {
257 Float number = (Float) value;
258 return new Float(-number.floatValue());
259 }
260 else {
261 throw new GroovyRuntimeException(
262 "Cannot negate type " + value.getClass().getName() + ", value "+value);
263 }
264 }
265
266 public static boolean isCase(Object switchValue, Object caseExpression) {
267 return asBool(invokeMethod(caseExpression, "isCase", new Object[] { switchValue }));
268 }
269
270 public static boolean compareIdentical(Object left, Object right) {
271 return left == right;
272 }
273
274 public static boolean compareEqual(Object left, Object right) {
275 return getInstance().objectsEqual(left, right);
276 }
277
278 public static Matcher findRegex(Object left, Object right) {
279 return getInstance().objectFindRegex(left, right);
280 }
281
282 public static boolean matchRegex(Object left, Object right) {
283 return getInstance().objectMatchRegex(left, right);
284 }
285
286 public static Pattern regexPattern(Object regex) {
287 return getInstance().regexPattern(regex);
288 }
289
290 public static boolean compareNotEqual(Object left, Object right) {
291 return !getInstance().objectsEqual(left, right);
292 }
293
294 public static boolean compareLessThan(Object left, Object right) {
295 return getInstance().compareTo(left, right) < 0;
296 }
297
298 public static boolean compareLessThanEqual(Object left, Object right) {
299 return getInstance().compareTo(left, right) <= 0;
300 }
301
302 public static boolean compareGreaterThan(Object left, Object right) {
303 return getInstance().compareTo(left, right) > 0;
304 }
305
306 public static boolean compareGreaterThanEqual(Object left, Object right) {
307 return getInstance().compareTo(left, right) >= 0;
308 }
309
310 public static Integer compareTo(Object left, Object right) {
311 int answer = getInstance().compareTo(left, right);
312 if (answer == 0) {
313 return ZERO;
314 }
315 else {
316 return answer > 0 ? ONE : MINUS_ONE;
317 }
318 }
319
320 public static Tuple createTuple(Object[] array) {
321 return new Tuple(array);
322 }
323
324 public static List createList(Object[] values) {
325 ArrayList answer = new ArrayList(values.length);
326 for (int i = 0; i < values.length; i++) {
327 answer.add(values[i]);
328 }
329 return answer;
330 }
331
332 public static Map createMap(Object[] values) {
333 Map answer = new HashMap(values.length / 2);
334 int i = 0;
335 while (i < values.length) {
336 answer.put(values[i++], values[i++]);
337 }
338 return answer;
339 }
340
341 public static List createRange(Object from, Object to, boolean inclusive) {
342 if (!inclusive) {
343 if (compareGreaterThan(from, to)) {
344 to = invokeMethod(to, "next", EMPTY_ARGS);
345 }
346 else {
347 to = invokeMethod(to, "previous", EMPTY_ARGS);
348 }
349 }
350 if (from instanceof Integer && to instanceof Integer) {
351 return new IntRange(asInt(from), asInt(to));
352 }
353 else {
354 return new ObjectRange((Comparable) from, (Comparable) to);
355 }
356 }
357
358 public static int asInt(Object value) {
359 return getInstance().asInt(value);
360 }
361
362 public static void assertFailed(Object expression, Object message) {
363 if (message == null || "".equals(message)) {
364 throw new AssertionError("Expression: " + expression);
365 }
366 else {
367 throw new AssertionError("" + message + ". Expression: " + expression);
368 }
369 }
370
371 public static Object runScript(Class scriptClass, String[] args) {
372 Binding context = new Binding(args);
373 Script script = createScript(scriptClass, context);
374 return invokeMethod(script, "run", EMPTY_ARGS);
375 }
376
377 public static Script createScript(Class scriptClass, Binding context) {
378 try {
379 final GroovyObject object = (GroovyObject) scriptClass.newInstance();
380 Script script = null;
381 if (object instanceof Script) {
382 script = (Script) object;
383 }
384 else {
385
386
387 script = new Script() {
388 public Object run() {
389 object.invokeMethod("main", EMPTY_MAIN_ARGS);
390 return null;
391 }
392 };
393 setProperties(object, context.getVariables());
394 }
395 script.setBinding(context);
396 return script;
397 }
398 catch (Exception e) {
399 throw new GroovyRuntimeException(
400 "Failed to create Script instance for class: " + scriptClass + ". Reason: " + e,
401 e);
402 }
403 }
404
405 /***
406 * Sets the properties on the given object
407 *
408 * @param object
409 * @param map
410 */
411 public static void setProperties(Object object, Map map) {
412 getMetaClass(object).setProperties(object, map);
413 }
414
415 public static String getVersion() {
416 String version = null;
417 Package p = Package.getPackage("groovy.lang");
418 if (p != null) {
419 version = p.getImplementationVersion();
420 }
421 if (version == null) {
422 version = "";
423 }
424 return version;
425 }
426
427 /***
428 * Allows conversion of arrays into a mutable List
429 *
430 * @return the array as a List
431 */
432 protected static List primitiveArrayToList(Object array) {
433 int size = Array.getLength(array);
434 List list = new ArrayList(size);
435 for (int i = 0; i < size; i++) {
436 list.add(Array.get(array, i));
437 }
438 return list;
439 }
440
441 /***
442 * Writes the given object to the given stream
443 */
444 public static void write(Writer out, Object object) throws IOException {
445 if (object instanceof String) {
446 out.write((String) object);
447 }
448 else if (object instanceof Writable) {
449 Writable writable = (Writable) object;
450 writable.writeTo(out);
451 }
452 else if (object instanceof InputStream || object instanceof Reader) {
453
454 Reader reader;
455 if (object instanceof InputStream) {
456 reader = new InputStreamReader((InputStream)object);
457 } else {
458 reader = (Reader) object;
459 }
460 char[] chars = new char[8192];
461 int i;
462 while ((i = reader.read(chars)) != -1) {
463 out.write(chars, 0, i);
464 }
465 reader.close();
466 }
467 else {
468 out.write(toString(object));
469 }
470 }
471
472 public static Object box(boolean value) {
473 return value ? Boolean.TRUE : Boolean.FALSE;
474 }
475
476 public static Object box(byte value) {
477 return new Byte(value);
478 }
479
480 public static Object box(char value) {
481 return new Character(value);
482 }
483
484 public static Object box(short value) {
485 return new Short(value);
486 }
487
488 public static Object box(int value) {
489 return integerValue(value);
490 }
491
492 public static Object box(long value) {
493 return new Long(value);
494 }
495
496 public static Object box(float value) {
497 return new Float(value);
498 }
499
500 public static Object box(double value) {
501 return new Double(value);
502 }
503
504 public static byte byteUnbox(Object value) {
505 Number n = (Number) asType(value, Byte.class);
506 return n.byteValue();
507 }
508
509 public static char charUnbox(Object value) {
510 Character n = (Character) asType(value, Character.class);
511 return n.charValue();
512 }
513
514 public static short shortUnbox(Object value) {
515 Number n = (Number) asType(value, Short.class);
516 return n.shortValue();
517 }
518
519 public static int intUnbox(Object value) {
520 Number n = (Number) asType(value, Integer.class);
521 return n.intValue();
522 }
523
524 public static boolean booleanUnbox(Object value) {
525 Boolean n = (Boolean) asType(value, Boolean.class);
526 return n.booleanValue();
527 }
528
529 public static long longUnbox(Object value) {
530 Number n = (Number) asType(value, Long.class);
531 return n.longValue();
532 }
533
534 public static float floatUnbox(Object value) {
535 Number n = (Number) asType(value, Float.class);
536 return n.floatValue();
537 }
538
539 public static double doubleUnbox(Object value) {
540 Number n = (Number) asType(value, Double.class);
541 return n.doubleValue();
542 }
543
544 /***
545 *
546 * @param a array of primitives
547 * @param type component type of the array
548 * @return
549 */
550 public static Object[] convertPrimitiveArray(Object a, Class type) {
551
552 Object[] ans = null;
553 String elemType = type.getName();
554 if (elemType.equals("int")) {
555
556 if (a.getClass().getName().equals("[Ljava.lang.Integer;")) {
557 ans = (Integer[])a;
558 }
559 else {
560 int[] ia = (int[])a;
561 ans = new Integer[ia.length];
562 for (int i = 0; i < ia.length; i++) {
563 int e = ia[i];
564 ans[i] = integerValue(e);
565 }
566 }
567 }
568 else if(elemType.equals("char")) {
569 if (a.getClass().getName().equals("[Ljava.lang.Character;")) {
570 ans = (Character[])a;
571 }
572 else {
573 char[] ia = (char[])a;
574 ans = new Character[ia.length];
575 for (int i = 0; i < ia.length; i++) {
576 char e = ia[i];
577 ans[i] = new Character(e);
578 }
579 }
580 }
581 else if(elemType.equals("boolean")) {
582 if (a.getClass().getName().equals("[Ljava.lang.Boolean;")) {
583 ans = (Boolean[])a;
584 }
585 else {
586 boolean[] ia = (boolean[])a;
587 ans = new Boolean[ia.length];
588 for (int i = 0; i < ia.length; i++) {
589 boolean e = ia[i];
590 ans[i] = new Boolean(e);
591 }
592 }
593 }
594 else if(elemType.equals("byte")) {
595 if (a.getClass().getName().equals("[Ljava.lang.Byte;")) {
596 ans = (Byte[])a;
597 }
598 else {
599 byte[] ia = (byte[])a;
600 ans = new Byte[ia.length];
601 for (int i = 0; i < ia.length; i++) {
602 byte e = ia[i];
603 ans[i] = new Byte(e);
604 }
605 }
606 }
607 else if(elemType.equals("short")) {
608 if (a.getClass().getName().equals("[Ljava.lang.Short;")) {
609 ans = (Short[])a;
610 }
611 else {
612 short[] ia = (short[])a;
613 ans = new Short[ia.length];
614 for (int i = 0; i < ia.length; i++) {
615 short e = ia[i];
616 ans[i] = new Short(e);
617 }
618 }
619 }
620 else if(elemType.equals("float")) {
621 if (a.getClass().getName().equals("[Ljava.lang.Float;")) {
622 ans = (Float[])a;
623 }
624 else {
625 float[] ia = (float[])a;
626 ans = new Float[ia.length];
627 for (int i = 0; i < ia.length; i++) {
628 float e = ia[i];
629 ans[i] = new Float(e);
630 }
631 }
632 }
633 else if(elemType.equals("long")) {
634 if (a.getClass().getName().equals("[Ljava.lang.Long;")) {
635 ans = (Long[])a;
636 }
637 else {
638 long[] ia = (long[])a;
639 ans = new Long[ia.length];
640 for (int i = 0; i < ia.length; i++) {
641 long e = ia[i];
642 ans[i] = new Long(e);
643 }
644 }
645 }
646 else if(elemType.equals("double")) {
647 if (a.getClass().getName().equals("[Ljava.lang.Double;")) {
648 ans = (Double[])a;
649 }
650 else {
651 double[] ia = (double[])a;
652 ans = new Double[ia.length];
653 for (int i = 0; i < ia.length; i++) {
654 double e = ia[i];
655 ans[i] = new Double(e);
656 }
657 }
658 }
659 return ans;
660 }
661
662 public static int[] convertToIntArray(Object a){
663 int[] ans = null;
664
665
666 if (a.getClass().getName().equals("[I")) {
667 ans = (int[])a;
668 }
669 else {
670 Object[] ia = (Object[])a;
671 ans = new int[ia.length];
672 for (int i = 0; i < ia.length; i++) {
673 ans[i] = ((Number)ia[i]).intValue();
674 }
675 }
676 return ans;
677 }
678
679 public static boolean[] convertToBooleanArray(Object a){
680 boolean[] ans = null;
681
682
683 if (a.getClass().getName().equals("[Z")) {
684 ans = (boolean[])a;
685 }
686 else {
687 Object[] ia = (Object[])a;
688 ans = new boolean[ia.length];
689 for (int i = 0; i < ia.length; i++) {
690 ans[i] = ((Boolean)ia[i]).booleanValue();
691 }
692 }
693 return ans;
694 }
695 public static byte[] convertToByteArray(Object a){
696 byte[] ans = null;
697
698
699 if (a.getClass().getName().equals("[B")) {
700 ans = (byte[])a;
701 }
702 else {
703 Object[] ia = (Object[])a;
704 ans = new byte[ia.length];
705 for (int i = 0; i < ia.length; i++) {
706 ans[i] = ((Number)ia[i]).byteValue();
707 }
708 }
709 return ans;
710 }
711 public static short[] convertToShortArray(Object a){
712 short[] ans = null;
713
714
715 if (a.getClass().getName().equals("[S")) {
716 ans = (short[])a;
717 }
718 else {
719 Object[] ia = (Object[])a;
720 ans = new short[ia.length];
721 for (int i = 0; i < ia.length; i++) {
722 ans[i] = ((Number)ia[i]).shortValue();
723 }
724 }
725 return ans;
726 }
727
728 public static char[] convertToCharArray(Object a){
729 char[] ans = null;
730
731
732 if (a.getClass().getName().equals("[C")) {
733 ans = (char[])a;
734 }
735 else {
736 Object[] ia = (Object[])a;
737 ans = new char[ia.length];
738 for (int i = 0; i < ia.length; i++) {
739 ans[i] = ((Character)ia[i]).charValue();
740 }
741 }
742 return ans;
743 }
744
745 public static long[] convertToLongArray(Object a){
746 long[] ans = null;
747
748
749 if (a.getClass().getName().equals("[J")) {
750 ans = (long[])a;
751 }
752 else {
753 Object[] ia = (Object[])a;
754 ans = new long[ia.length];
755 for (int i = 0; i < ia.length; i++) {
756 ans[i] = ((Number)ia[i]).longValue();
757 }
758 }
759 return ans;
760 }
761
762 public static float[] convertToFloatArray(Object a){
763 float[] ans = null;
764
765
766 if (a.getClass().getName().equals("[F")) {
767 ans = (float[])a;
768 }
769 else {
770 Object[] ia = (Object[])a;
771 ans = new float[ia.length];
772 for (int i = 0; i < ia.length; i++) {
773 ans[i] = ((Number)ia[i]).floatValue();
774 }
775 }
776 return ans;
777 }
778
779 public static double[] convertToDoubleArray(Object a){
780 double[] ans = null;
781
782
783 if (a.getClass().getName().equals("[D")) {
784 ans = (double[])a;
785 }
786 else {
787 Object[] ia = (Object[])a;
788 ans = new double[ia.length];
789 for (int i = 0; i < ia.length; i++) {
790 ans[i] = ((Number)ia[i]).doubleValue();
791 }
792 }
793 return ans;
794 }
795
796 public static Object convertToPrimitiveArray(Object a, Class type) {
797 if (type == Byte.TYPE)
798 return convertToByteArray(a);
799 if (type == Boolean.TYPE)
800 return convertToBooleanArray(a);
801 if (type == Short.TYPE)
802 return convertToShortArray(a);
803 if (type == Character.TYPE)
804 return convertToCharArray(a);
805 if (type == Integer.TYPE)
806 return convertToIntArray(a);
807 if (type == Long.TYPE)
808 return convertToLongArray(a);
809 if (type == Float.TYPE)
810 return convertToFloatArray(a);
811 if (type == Double.TYPE)
812 return convertToDoubleArray(a);
813 else
814 return a;
815 }
816
817 /***
818 * get the Integer object from an int. Cached version is used for small ints.
819 * @param v
820 * @return
821 */
822 public static Integer integerValue(int v) {
823 int index = v + INT_CACHE_OFFSET;
824 if (index >= 0 && index < INT_CACHE_LEN ) {
825 return SMALL_INTEGERS[index];
826 }
827 else {
828 return new Integer(v);
829 }
830 }
831
832 private static Integer[] SMALL_INTEGERS;
833 private static int INT_CACHE_OFFSET = 128, INT_CACHE_LEN = 256;
834 static {
835 SMALL_INTEGERS = new Integer[INT_CACHE_LEN];
836 for (int i = 0; i < SMALL_INTEGERS.length; i++) {
837 SMALL_INTEGERS[i] = new Integer(i - INT_CACHE_OFFSET);
838 }
839 }
840 }