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