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