1 /*
2 * Copyright 2003-2008 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.codehaus.groovy.runtime;
17
18 import groovy.lang;
19 import groovy.xml.XmlUtil;
20 import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
21 import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
22 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
23 import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
24 import org.w3c.dom.Element;
25
26 import java.beans.Introspector;
27 import java.io;
28 import java.math.BigDecimal;
29 import java.math.BigInteger;
30 import java.util;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 /**
35 * A static helper class to make bytecode generation easier and act as a facade over the Invoker
36 *
37 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
38 * @version $Revision: 16276 $
39 */
40 public class InvokerHelper {
41 private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
42
43 public static final Object[] EMPTY_ARGS = {};
44 protected static final Object[] EMPTY_ARGUMENTS = EMPTY_ARGS;
45 protected static final Class[] EMPTY_TYPES = {};
46
47 public static final MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
48
49 public static void removeClass(Class clazz) {
50 metaRegistry.removeMetaClass(clazz);
51 Introspector.flushFromCaches(clazz);
52 }
53
54 public static Object invokeMethodSafe(Object object, String methodName, Object arguments) {
55 if (object != null) {
56 return invokeMethod(object, methodName, arguments);
57 }
58 return null;
59 }
60
61 public static Object invokeStaticMethod(String klass, String methodName, Object arguments) throws ClassNotFoundException {
62 Class type = Class.forName(klass);
63 return invokeStaticMethod(type, methodName, arguments);
64 }
65
66
67 public static Object invokeStaticNoArgumentsMethod(Class type, String methodName) {
68 return invokeStaticMethod(type, methodName, EMPTY_ARGS);
69 }
70
71 public static Object invokeConstructorOf(String klass, Object arguments) throws ClassNotFoundException {
72 Class type = Class.forName(klass);
73 return invokeConstructorOf(type, arguments);
74 }
75
76 public static Object invokeNoArgumentsConstructorOf(Class type) {
77 return invokeConstructorOf(type, EMPTY_ARGS);
78 }
79
80 public static Object invokeClosure(Object closure, Object arguments) {
81 return invokeMethod(closure, "doCall", arguments);
82 }
83
84 public static List asList(Object value) {
85 if (value == null) {
86 return Collections.EMPTY_LIST;
87 }
88 if (value instanceof List) {
89 return (List) value;
90 }
91 if (value.getClass().isArray()) {
92 return Arrays.asList((Object[]) value);
93 }
94 if (value instanceof Enumeration) {
95 List answer = new ArrayList();
96 for (Enumeration e = (Enumeration) value; e.hasMoreElements();) {
97 answer.add(e.nextElement());
98 }
99 return answer;
100 }
101 // lets assume its a collection of 1
102 return Collections.singletonList(value);
103 }
104
105 public static String toString(Object arguments) {
106 if (arguments instanceof Object[])
107 return toArrayString((Object[]) arguments);
108 if (arguments instanceof Collection)
109 return toListString((Collection) arguments);
110 if (arguments instanceof Map)
111 return toMapString((Map) arguments);
112 return format(arguments, false);
113 }
114
115 public static String inspect(Object self) {
116 return format(self, true);
117 }
118
119 public static Object getAttribute(Object object, String attribute) {
120 if (object == null) {
121 object = NullObject.getNullObject();
122 }
123
124 if (object instanceof Class) {
125 return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
126 } else if (object instanceof GroovyObject) {
127 return ((GroovyObject) object).getMetaClass().getAttribute(object, attribute);
128 } else {
129 return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
130 }
131 }
132
133 public static void setAttribute(Object object, String attribute, Object newValue) {
134 if (object == null) {
135 object = NullObject.getNullObject();
136 }
137
138 if (object instanceof Class) {
139 metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
140 } else if (object instanceof GroovyObject) {
141 ((GroovyObject) object).getMetaClass().setAttribute(object, attribute, newValue);
142 } else {
143 metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
144 }
145 }
146
147 public static Object getProperty(Object object, String property) {
148 if (object == null) {
149 object = NullObject.getNullObject();
150 }
151
152 if (object instanceof GroovyObject) {
153 GroovyObject pogo = (GroovyObject) object;
154 return pogo.getProperty(property);
155 } else if (object instanceof Class) {
156 Class c = (Class) object;
157 return metaRegistry.getMetaClass(c).getProperty(object, property);
158 } else {
159 return ((MetaClassRegistryImpl)metaRegistry).getMetaClass(object).getProperty(object, property);
160 }
161 }
162
163 public static Object getPropertySafe(Object object, String property) {
164 if (object != null) {
165 return getProperty(object, property);
166 }
167 return null;
168 }
169
170 public static void setProperty(Object object, String property, Object newValue) {
171 if (object == null) {
172 object = NullObject.getNullObject();
173 }
174
175 if (object instanceof GroovyObject) {
176 GroovyObject pogo = (GroovyObject) object;
177 pogo.setProperty(property, newValue);
178 } else if (object instanceof Class) {
179 metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue);
180 } else {
181 ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object).setProperty(object, property, newValue);
182 }
183 }
184
185 /**
186 * This is so we don't have to reorder the stack when we call this method.
187 * At some point a better name might be in order.
188 */
189 public static void setProperty2(Object newValue, Object object, String property) {
190 setProperty(object, property, newValue);
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 setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
199 object.setProperty(property, newValue);
200 }
201
202 public static Object getGroovyObjectProperty(GroovyObject object, String property) {
203 return object.getProperty(property);
204 }
205
206
207 /**
208 * This is so we don't have to reorder the stack when we call this method.
209 * At some point a better name might be in order.
210 */
211 public static void setPropertySafe2(Object newValue, Object object, String property) {
212 if (object != null) {
213 setProperty2(newValue, object, property);
214 }
215 }
216
217 /**
218 * Returns the method pointer for the given object name
219 */
220 public static Closure getMethodPointer(Object object, String methodName) {
221 if (object == null) {
222 throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
223 }
224 return new MethodClosure(object, methodName);
225 }
226
227 public static Object unaryMinus(Object value) {
228 if (value instanceof Integer) {
229 Integer number = (Integer) value;
230 return Integer.valueOf(-number.intValue());
231 }
232 if (value instanceof Long) {
233 Long number = (Long) value;
234 return new Long(-number.longValue());
235 }
236 if (value instanceof BigInteger) {
237 return ((BigInteger) value).negate();
238 }
239 if (value instanceof BigDecimal) {
240 return ((BigDecimal) value).negate();
241 }
242 if (value instanceof Double) {
243 Double number = (Double) value;
244 return new Double(-number.doubleValue());
245 }
246 if (value instanceof Float) {
247 Float number = (Float) value;
248 return new Float(-number.floatValue());
249 }
250 if (value instanceof ArrayList) {
251 // value is an list.
252 List newlist = new ArrayList();
253 Iterator it = ((ArrayList) value).iterator();
254 for (; it.hasNext();) {
255 newlist.add(unaryMinus(it.next()));
256 }
257 return newlist;
258 }
259 return invokeMethod(value, "negative", EMPTY_ARGS);
260 }
261
262 public static Object unaryPlus(Object value) {
263 if (value instanceof Integer ||
264 value instanceof Long ||
265 value instanceof BigInteger ||
266 value instanceof BigDecimal ||
267 value instanceof Double ||
268 value instanceof Float) {
269 return value;
270 }
271 if (value instanceof ArrayList) {
272 // value is an list.
273 List newlist = new ArrayList();
274 Iterator it = ((ArrayList) value).iterator();
275 for (; it.hasNext();) {
276 newlist.add(unaryPlus(it.next()));
277 }
278 return newlist;
279 }
280 return invokeMethod(value, "positive", EMPTY_ARGS);
281 }
282
283 /**
284 * Find the right hand regex within the left hand string and return a matcher.
285 *
286 * @param left string to compare
287 * @param right regular expression to compare the string to
288 */
289 public static Matcher findRegex(Object left, Object right) {
290 String stringToCompare;
291 if (left instanceof String) {
292 stringToCompare = (String) left;
293 } else {
294 stringToCompare = toString(left);
295 }
296 String regexToCompareTo;
297 if (right instanceof String) {
298 regexToCompareTo = (String) right;
299 } else if (right instanceof Pattern) {
300 Pattern pattern = (Pattern) right;
301 return pattern.matcher(stringToCompare);
302 } else {
303 regexToCompareTo = toString(right);
304 }
305 Matcher matcher = Pattern.compile(regexToCompareTo).matcher(stringToCompare);
306 return matcher;
307 }
308
309
310 /**
311 * Find the right hand regex within the left hand string and return a matcher.
312 *
313 * @param left string to compare
314 * @param right regular expression to compare the string to
315 */
316 public static boolean matchRegex(Object left, Object right) {
317 Pattern pattern;
318 if (right instanceof Pattern) {
319 pattern = (Pattern) right;
320 } else {
321 pattern = Pattern.compile(toString(right));
322 }
323 String stringToCompare = toString(left);
324 Matcher matcher = pattern.matcher(stringToCompare);
325 RegexSupport.setLastMatcher(matcher);
326 return matcher.matches();
327 }
328
329 public static Tuple createTuple(Object[] array) {
330 return new Tuple(array);
331 }
332
333 public static SpreadMap spreadMap(Object value) {
334 if (value instanceof Map) {
335 Object[] values = new Object[((Map) value).keySet().size() * 2];
336 int index = 0;
337 Iterator it = ((Map) value).keySet().iterator();
338 for (; it.hasNext();) {
339 Object key = it.next();
340 values[index++] = key;
341 values[index++] = ((Map) value).get(key);
342 }
343 return new SpreadMap(values);
344 }
345 throw new SpreadMapEvaluatingException("Cannot spread the map " + value.getClass().getName() + ", value " + value);
346 }
347
348 public static List createList(Object[] values) {
349 List answer = new ArrayList(values.length);
350 answer.addAll(Arrays.asList(values));
351 return answer;
352 }
353
354 public static Map createMap(Object[] values) {
355 Map answer = new LinkedHashMap(values.length / 2);
356 int i = 0;
357 while (i < values.length - 1) {
358 if ((values[i] instanceof SpreadMap) && (values[i + 1] instanceof Map)) {
359 Map smap = (Map) values[i + 1];
360 Iterator iter = smap.keySet().iterator();
361 for (; iter.hasNext();) {
362 Object key = iter.next();
363 answer.put(key, smap.get(key));
364 }
365 i += 2;
366 } else {
367 answer.put(values[i++], values[i++]);
368 }
369 }
370 return answer;
371 }
372
373 public static void assertFailed(Object expression, Object message) {
374 if (message == null || "".equals(message)) {
375 throw new AssertionError("Expression: " + expression);
376 }
377 throw new AssertionError(String.valueOf(message) + ". Expression: " + expression);
378 }
379
380 public static Object runScript(Class scriptClass, String[] args) {
381 Binding context = new Binding(args);
382 Script script = createScript(scriptClass, context);
383 return invokeMethod(script, "run", EMPTY_ARGS);
384 }
385
386 public static Script createScript(Class scriptClass, Binding context) {
387 Script script = null;
388 // for empty scripts
389 if (scriptClass == null) {
390 script = new Script() {
391 public Object run() {
392 return null;
393 }
394 };
395 } else {
396 try {
397 final GroovyObject object = (GroovyObject) scriptClass
398 .newInstance();
399 if (object instanceof Script) {
400 script = (Script) object;
401 } else {
402 // it could just be a class, so lets wrap it in a Script
403 // wrapper
404 // though the bindings will be ignored
405 script = new Script() {
406 public Object run() {
407 Object args = getBinding().getVariables().get("args");
408 Object argsToPass = EMPTY_MAIN_ARGS;
409 if(args != null && args instanceof String[]) {
410 argsToPass = args;
411 }
412 object.invokeMethod("main", argsToPass);
413 return null;
414 }
415 };
416 setProperties(object, context.getVariables());
417 }
418 } catch (Exception e) {
419 throw new GroovyRuntimeException(
420 "Failed to create Script instance for class: "
421 + scriptClass + ". Reason: " + e, e);
422 }
423 }
424 script.setBinding(context);
425 return script;
426 }
427
428 /**
429 * Sets the properties on the given object
430 */
431 public static void setProperties(Object object, Map map) {
432 MetaClass mc = getMetaClass(object);
433 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
434 Map.Entry entry = (Map.Entry) iter.next();
435 String key = entry.getKey().toString();
436
437 Object value = entry.getValue();
438 try {
439 mc.setProperty(object, key, value);
440 } catch (MissingPropertyException mpe) {
441 // Ignore
442 }
443 }
444 }
445
446 public static String getVersion() {
447 String version = null;
448 Package p = Package.getPackage("groovy.lang");
449 if (p != null) {
450 version = p.getImplementationVersion();
451 }
452 if (version == null) {
453 version = "";
454 }
455 return version;
456 }
457
458 /**
459 * Writes the given object to the given stream
460 */
461 public static void write(Writer out, Object object) throws IOException {
462 if (object instanceof String) {
463 out.write((String) object);
464 } else if (object instanceof Object[]) {
465 out.write(toArrayString((Object[]) object));
466 } else if (object instanceof Map) {
467 out.write(toMapString((Map) object));
468 } else if (object instanceof Collection) {
469 out.write(toListString((Collection) object));
470 } else if (object instanceof Writable) {
471 Writable writable = (Writable) object;
472 writable.writeTo(out);
473 } else if (object instanceof InputStream || object instanceof Reader) {
474 // Copy stream to stream
475 Reader reader;
476 if (object instanceof InputStream) {
477 reader = new InputStreamReader((InputStream) object);
478 } else {
479 reader = (Reader) object;
480 }
481 char[] chars = new char[8192];
482 int i;
483 while ((i = reader.read(chars)) != -1) {
484 out.write(chars, 0, i);
485 }
486 reader.close();
487 } else {
488 out.write(toString(object));
489 }
490 }
491
492 public static Iterator asIterator(Object o) {
493 return (Iterator) invokeMethod(o, "iterator", EMPTY_ARGS);
494 }
495
496 protected static String format(Object arguments, boolean verbose) {
497 if (arguments == null) {
498 final NullObject nullObject = NullObject.getNullObject();
499 return (String) nullObject.getMetaClass().invokeMethod(nullObject, "toString", EMPTY_ARGS);
500 }
501 if (arguments.getClass().isArray()) {
502 if (arguments instanceof char[]) {
503 return new String((char[]) arguments);
504 }
505 return format(DefaultTypeTransformation.asCollection(arguments), verbose);
506 }
507 if (arguments instanceof Range) {
508 Range range = (Range) arguments;
509 if (verbose) {
510 return range.inspect();
511 } else {
512 return range.toString();
513 }
514 }
515 if (arguments instanceof Collection) {
516 return formatList((Collection) arguments, verbose);
517 }
518 if (arguments instanceof Map) {
519 return formatMap((Map) arguments, verbose);
520 }
521 if (arguments instanceof Element) {
522 return XmlUtil.serialize((Element) arguments);
523 }
524 if (arguments instanceof String) {
525 if (verbose) {
526 String arg = ((String) arguments).replaceAll("\\n", "\\\\n"); // line feed
527 arg = arg.replaceAll("\\r", "\\\\r"); // carriage return
528 arg = arg.replaceAll("\\t", "\\\\t"); // tab
529 arg = arg.replaceAll("\\f", "\\\\f"); // form feed
530 arg = arg.replaceAll("\\\"", "\\\\\""); // double quotation mark
531 arg = arg.replaceAll("\\\\", "\\\\"); // backslash
532 return "\"" + arg + "\"";
533 } else {
534 return (String) arguments;
535 }
536 }
537 // TODO: For GROOVY-2599 do we need something like below but it breaks other things
538 // return (String) invokeMethod(arguments, "toString", EMPTY_ARGS);
539 return arguments.toString();
540 }
541
542 private static String formatMap(Map map, boolean verbose) {
543 if (map.isEmpty()) {
544 return "[:]";
545 }
546 StringBuffer buffer = new StringBuffer("[");
547 boolean first = true;
548 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
549 if (first) {
550 first = false;
551 } else {
552 buffer.append(", ");
553 }
554 Map.Entry entry = (Map.Entry) iter.next();
555 buffer.append(format(entry.getKey(), verbose));
556 buffer.append(":");
557 if (entry.getValue() == map) {
558 buffer.append("this Map_");
559 } else {
560 buffer.append(format(entry.getValue(), verbose));
561 }
562 }
563 buffer.append("]");
564 return buffer.toString();
565 }
566
567 private static String formatList(Collection list, boolean verbose) {
568 StringBuffer buffer = new StringBuffer("[");
569 boolean first = true;
570 for (Iterator iter = list.iterator(); iter.hasNext();) {
571 if (first) {
572 first = false;
573 } else {
574 buffer.append(", ");
575 }
576 buffer.append(format(iter.next(), verbose));
577 }
578 buffer.append("]");
579 return buffer.toString();
580 }
581
582 /**
583 * A helper method to format the arguments types as a comma-separated list.
584 *
585 * @param arguments the type to process
586 * @return the string representation of the type
587 */
588 public static String toTypeString(Object[] arguments) {
589 if (arguments == null) {
590 return "null";
591 }
592 StringBuffer argBuf = new StringBuffer();
593 for (int i = 0; i < arguments.length; i++) {
594 if (i > 0) {
595 argBuf.append(", ");
596 }
597 argBuf.append(arguments[i] != null ? arguments[i].getClass().getName() : "null");
598 }
599 return argBuf.toString();
600 }
601
602 /**
603 * A helper method to return the string representation of a map with bracket boundaries "[" and "]".
604 *
605 * @param arg the map to process
606 * @return the string representation of the map
607 */
608 public static String toMapString(Map arg) {
609 return formatMap(arg, false);
610 }
611
612 /**
613 * A helper method to return the string representation of a list with bracket boundaries "[" and "]".
614 *
615 * @param arg the collection to process
616 * @return the string representation of the collection
617 */
618 public static String toListString(Collection arg) {
619 return formatList(arg, false);
620 }
621
622 /**
623 * A helper method to return the string representation of an array of objects
624 * with brace boundaries "{" and "}".
625 *
626 * @param arguments the array to process
627 * @return the string representation of the array
628 */
629 public static String toArrayString(Object[] arguments) {
630 if (arguments == null) {
631 return "null";
632 }
633 String sbdry = "[";
634 String ebdry = "]";
635 StringBuffer argBuf = new StringBuffer(sbdry);
636 for (int i = 0; i < arguments.length; i++) {
637 if (i > 0) {
638 argBuf.append(", ");
639 }
640 argBuf.append(format(arguments[i], false));
641 }
642 argBuf.append(ebdry);
643 return argBuf.toString();
644 }
645
646 public static List createRange(Object from, Object to, boolean inclusive) {
647 try {
648 return ScriptBytecodeAdapter.createRange(from, to, inclusive);
649 } catch (RuntimeException re) {
650 throw re;
651 } catch (Error e) {
652 throw e;
653 } catch (Throwable t) {
654 throw new RuntimeException(t);
655 }
656 }
657
658 public static Object bitwiseNegate(Object value) {
659 if (value instanceof Integer) {
660 Integer number = (Integer) value;
661 return Integer.valueOf(~number.intValue());
662 }
663 if (value instanceof Long) {
664 Long number = (Long) value;
665 return new Long(~number.longValue());
666 }
667 if (value instanceof BigInteger) {
668 return ((BigInteger) value).not();
669 }
670 if (value instanceof String) {
671 // value is a regular expression.
672 return DefaultGroovyMethods.bitwiseNegate(value.toString());
673 }
674 if (value instanceof GString) {
675 // value is a regular expression.
676 return DefaultGroovyMethods.bitwiseNegate(value.toString());
677 }
678 if (value instanceof ArrayList) {
679 // value is an list.
680 List newlist = new ArrayList();
681 Iterator it = ((ArrayList) value).iterator();
682 for (; it.hasNext();) {
683 newlist.add(bitwiseNegate(it.next()));
684 }
685 return newlist;
686 }
687 return invokeMethod(value, "bitwiseNegate", EMPTY_ARGS);
688 }
689
690 public static MetaClassRegistry getMetaRegistry() {
691 return metaRegistry;
692 }
693
694 public static MetaClass getMetaClass(Object object) {
695 if (object instanceof GroovyObject)
696 return ((GroovyObject) object).getMetaClass();
697 else
698 return ((MetaClassRegistryImpl) GroovySystem.getMetaClassRegistry()).getMetaClass(object);
699 }
700
701 public static MetaClass getMetaClass(Class cls) {
702 return metaRegistry.getMetaClass(cls);
703 }
704
705 /**
706 * Invokes the given method on the object.
707 */
708 public static Object invokeMethod(Object object, String methodName, Object arguments) {
709 if (object == null) {
710 object = NullObject.getNullObject();
711 //throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
712 }
713
714 // if the object is a Class, call a static method from that class
715 if (object instanceof Class) {
716 Class theClass = (Class) object;
717 MetaClass metaClass = metaRegistry.getMetaClass(theClass);
718 return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
719 }
720
721 // it's an instance; check if it's a Java one
722 if (!(object instanceof GroovyObject)) {
723 return invokePojoMethod(object, methodName, arguments);
724 }
725
726 // a groovy instance (including builder, closure, ...)
727 return invokePogoMethod(object, methodName, arguments);
728 }
729
730 static Object invokePojoMethod(Object object, String methodName, Object arguments) {
731 MetaClass metaClass = InvokerHelper.getMetaClass(object);
732 return metaClass.invokeMethod(object, methodName, asArray(arguments));
733 }
734
735 static Object invokePogoMethod(Object object, String methodName, Object arguments) {
736 GroovyObject groovy = (GroovyObject) object;
737 boolean intercepting = groovy instanceof GroovyInterceptable;
738 try {
739 // if it's a pure interceptable object (even intercepting toString(), clone(), ...)
740 if (intercepting) {
741 return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
742 }
743 //else try a statically typed method or a GDK method
744 return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
745 } catch (MissingMethodException e) {
746 if (e instanceof MissingMethodExecutionFailed) {
747 throw (MissingMethodException) e.getCause();
748 } else if (!intercepting && e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
749 // in case there's nothing else, invoke the object's own invokeMethod()
750 return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
751 } else {
752 throw e;
753 }
754 }
755 }
756
757 public static Object invokeSuperMethod(Object object, String methodName, Object arguments) {
758 if (object == null) {
759 throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
760 }
761
762 Class theClass = object.getClass();
763
764 MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
765 return metaClass.invokeMethod(object, methodName, asArray(arguments));
766 }
767
768 public static Object invokeStaticMethod(Class type, String method, Object arguments) {
769 MetaClass metaClass = metaRegistry.getMetaClass(type);
770 return metaClass.invokeStaticMethod(type, method, asArray(arguments));
771 }
772
773 public static Object invokeConstructorOf(Class type, Object arguments) {
774 MetaClass metaClass = metaRegistry.getMetaClass(type);
775 return metaClass.invokeConstructor(asArray(arguments));
776 }
777
778 /**
779 * Converts the given object into an array; if its an array then just
780 * cast otherwise wrap it in an array
781 */
782 public static Object[] asArray(Object arguments) {
783
784 if (arguments == null) {
785 return EMPTY_ARGUMENTS;
786 }
787 if (arguments instanceof Object[]) {
788 return (Object[]) arguments;
789 }
790 return new Object[]{arguments};
791 }
792
793 public static Object[] asUnwrappedArray(Object arguments) {
794
795 Object[] args = asArray(arguments);
796
797 for (int i=0; i<args.length; i++) {
798 if (args[i] instanceof PojoWrapper) {
799 args[i] = ((PojoWrapper)args[i]).unwrap();
800 }
801 }
802
803 return args;
804 }
805 }