001    /*
002     $Id: InvokerHelper.java,v 1.70 2005/07/23 12:09:48 phk Exp $
003    
004     Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
005    
006     Redistribution and use of this software and associated documentation
007     ("Software"), with or without modification, are permitted provided
008     that the following conditions are met:
009    
010     1. Redistributions of source code must retain copyright
011        statements and notices.  Redistributions must also contain a
012        copy of this document.
013    
014     2. Redistributions in binary form must reproduce the
015        above copyright notice, this list of conditions and the
016        following disclaimer in the documentation and/or other
017        materials provided with the distribution.
018    
019     3. The name "groovy" must not be used to endorse or promote
020        products derived from this Software without prior written
021        permission of The Codehaus.  For written permission,
022        please contact info@codehaus.org.
023    
024     4. Products derived from this Software may not be called "groovy"
025        nor may "groovy" appear in their names without prior written
026        permission of The Codehaus. "groovy" is a registered
027        trademark of The Codehaus.
028    
029     5. Due credit should be given to The Codehaus -
030        http://groovy.codehaus.org/
031    
032     THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033     ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034     NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035     FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
036     THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037     INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039     SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041     STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042     ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043     OF THE POSSIBILITY OF SUCH DAMAGE.
044    
045     */
046    package org.codehaus.groovy.runtime;
047    
048    import groovy.lang.*;
049    
050    import java.beans.Introspector;
051    import java.io.IOException;
052    import java.io.InputStream;
053    import java.io.InputStreamReader;
054    import java.io.Reader;
055    import java.io.Writer;
056    import java.lang.reflect.Array;
057    import java.math.BigDecimal;
058    import java.math.BigInteger;
059    import java.util.ArrayList;
060    import java.util.Collection;
061    import java.util.HashMap;
062    import java.util.Iterator;
063    import java.util.List;
064    import java.util.Map;
065    import java.util.regex.Matcher;
066    import java.util.regex.Pattern;
067    
068    /**
069     * A static helper class to make bytecode generation easier and act as a facade over the Invoker
070     *
071     * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
072     * @version $Revision: 1.70 $
073     */
074    public class InvokerHelper {
075        public static final Object[] EMPTY_ARGS = {
076        };
077    
078        private static final Object[] EMPTY_MAIN_ARGS = new Object[]{new String[0]};
079    
080        private static final Invoker singleton = new Invoker();
081    
082        private static final Integer ZERO = new Integer(0);
083        private static final Integer MINUS_ONE = new Integer(-1);
084        private static final Integer ONE = new Integer(1);
085    
086        public static MetaClass getMetaClass(Object object) {
087            return getInstance().getMetaClass(object);
088        }
089    
090        public static void removeClass(Class clazz) {
091            getInstance().removeMetaClass(clazz);
092            Introspector.flushFromCaches(clazz);
093        }
094    
095        public static Invoker getInstance() {
096            return singleton;
097        }
098    
099        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            if (arguments instanceof Object[])
156                return getInstance().toArrayString((Object[])arguments);
157            else if (arguments instanceof Collection)
158                return getInstance().toListString((Collection)arguments);
159            else if (arguments instanceof Map)
160                return getInstance().toMapString((Map)arguments);
161            else
162                return getInstance().toString(arguments);
163        }
164    
165        public static String toTypeString(Object[] arguments) {
166            return getInstance().toTypeString(arguments);
167        }
168    
169        public static String toMapString(Map arg) {
170            return getInstance().toMapString(arg);
171        }
172    
173        public static String toListString(Collection arg) {
174            return getInstance().toListString(arg);
175        }
176    
177        public static String toArrayString(Object[] arguments) {
178            return getInstance().toArrayString(arguments);
179        }
180    
181        public static String inspect(Object self) {
182            return getInstance().inspect(self);
183        }
184    
185        public static Object getAttribute(Object object, String attribute) {
186            return getInstance().getAttribute(object, attribute);
187        }
188    
189        public static void setAttribute(Object object, String attribute, Object newValue) {
190            getInstance().setAttribute(object, attribute, newValue);
191        }
192    
193        public static Object getProperty(Object object, String property) {
194            return getInstance().getProperty(object, property);
195        }
196    
197        public static Object getPropertySafe(Object object, String property) {
198            if (object != null) {
199                return getInstance().getProperty(object, property);
200            }
201            return null;
202        }
203    
204        public static void setProperty(Object object, String property, Object newValue) {
205            getInstance().setProperty(object, property, newValue);
206        }
207    
208        /**
209         * This is so we don't have to reorder the stack when we call this method.
210         * At some point a better name might be in order.
211         */
212        public static void setProperty2(Object newValue, Object object, String property) {
213            getInstance().setProperty(object, property, newValue);
214        }
215    
216    
217        /**
218         * This is so we don't have to reorder the stack when we call this method.
219         * At some point a better name might be in order.
220         */
221        public static void setGroovyObjectProperty(Object newValue, GroovyObject object, String property) {
222            object.setProperty(property, newValue);
223        }
224    
225        public static Object getGroovyObjectProperty(GroovyObject object, String property) {
226            return object.getProperty(property);
227        }
228    
229    
230        /**
231         * This is so we don't have to reorder the stack when we call this method.
232         * At some point a better name might be in order.
233         */
234        public static void setPropertySafe2(Object newValue, Object object, String property) {
235            if (object != null) {
236                setProperty2(newValue, object, property);
237            }
238        }
239    
240        /**
241         * Returns the method pointer for the given object name
242         */
243        public static Closure getMethodPointer(Object object, String methodName) {
244            return getInstance().getMethodPointer(object, methodName);
245        }
246    
247        /**
248         * Provides a hook for type coercion of the given object to the required type
249         *
250         * @param type   of object to convert the given object to
251         * @param object the object to be converted
252         * @return the original object or a new converted value
253         */
254        public static Object asType(Object object, Class type) {
255            return getInstance().asType(object, type);
256        }
257    
258        public static boolean asBool(Object object) {
259            return getInstance().asBool(object);
260        }
261    
262        public static boolean notObject(Object object) {
263            return !asBool(object);
264        }
265    
266        public static boolean notBoolean(boolean bool) {
267            return !bool;
268        }
269    
270        public static Object negate(Object value) {
271            if (value instanceof Integer) {
272                Integer number = (Integer) value;
273                return integerValue(-number.intValue());
274            }
275            else if (value instanceof Long) {
276                Long number = (Long) value;
277                return new Long(-number.longValue());
278            }
279            else if (value instanceof BigInteger) {
280                return ((BigInteger) value).negate();
281            }
282            else if (value instanceof BigDecimal) {
283                return ((BigDecimal) value).negate();
284            }
285            else if (value instanceof Double) {
286                Double number = (Double) value;
287                return new Double(-number.doubleValue());
288            }
289            else if (value instanceof Float) {
290                Float number = (Float) value;
291                return new Float(-number.floatValue());
292            }
293            else if (value instanceof ArrayList) {
294                // value is an list.
295                ArrayList newlist = new ArrayList();
296                Iterator it = ((ArrayList) value).iterator();
297                for (; it.hasNext();) {
298                    newlist.add(negate(it.next()));
299                }
300                return newlist;
301            }
302            else {
303                throw new GroovyRuntimeException("Cannot negate type " + value.getClass().getName() + ", value " + value);
304            }
305        }
306    
307        public static Object bitNegate(Object value) {
308            if (value instanceof Integer) {
309                Integer number = (Integer) value;
310                return integerValue(~number.intValue());
311            }
312            else if (value instanceof Long) {
313                Long number = (Long) value;
314                return new Long(~number.longValue());
315            }
316            else if (value instanceof BigInteger) {
317                return ((BigInteger) value).not();
318            }
319            else if (value instanceof String) {
320                // value is a regular expression.
321                return getInstance().regexPattern(value);
322            }
323            else if (value instanceof GString) {
324                // value is a regular expression.
325                return getInstance().regexPattern(value.toString());
326            }
327            else if (value instanceof ArrayList) {
328                // value is an list.
329                ArrayList newlist = new ArrayList();
330                Iterator it = ((ArrayList) value).iterator();
331                for (; it.hasNext();) {
332                    newlist.add(bitNegate(it.next()));
333                }
334                return newlist;
335            }
336            else {
337                throw new BitwiseNegateEvaluatingException("Cannot bitwise negate type " + value.getClass().getName() + ", value " + value);
338            }
339        }
340    
341        public static boolean isCase(Object switchValue, Object caseExpression) {
342            return asBool(invokeMethod(caseExpression, "isCase", new Object[]{switchValue}));
343        }
344    
345        public static boolean compareIdentical(Object left, Object right) {
346            return left == right;
347        }
348    
349        public static boolean compareEqual(Object left, Object right) {
350            return getInstance().objectsEqual(left, right);
351        }
352    
353        public static Matcher findRegex(Object left, Object right) {
354            return getInstance().objectFindRegex(left, right);
355        }
356    
357        public static boolean matchRegex(Object left, Object right) {
358            return getInstance().objectMatchRegex(left, right);
359        }
360    
361        public static Pattern regexPattern(Object regex) {
362            return getInstance().regexPattern(regex);
363        }
364    
365        public static boolean compareNotEqual(Object left, Object right) {
366            return !getInstance().objectsEqual(left, right);
367        }
368    
369        public static boolean compareLessThan(Object left, Object right) {
370            return getInstance().compareTo(left, right) < 0;
371        }
372    
373        public static boolean compareLessThanEqual(Object left, Object right) {
374            return getInstance().compareTo(left, right) <= 0;
375        }
376    
377        public static boolean compareGreaterThan(Object left, Object right) {
378            return getInstance().compareTo(left, right) > 0;
379        }
380    
381        public static boolean compareGreaterThanEqual(Object left, Object right) {
382            return getInstance().compareTo(left, right) >= 0;
383        }
384    
385        public static Integer compareTo(Object left, Object right) {
386            int answer = getInstance().compareTo(left, right);
387            if (answer == 0) {
388                return ZERO;
389            }
390            else {
391                return answer > 0 ? ONE : MINUS_ONE;
392            }
393        }
394    
395        public static Tuple createTuple(Object[] array) {
396            return new Tuple(array);
397        }
398    
399        public static SpreadList spreadList(Object value) {
400            if (value instanceof List) {
401                // value is a list.
402                Object[] values = new Object[((List) value).size()];
403                int index = 0;
404                Iterator it = ((List) value).iterator();
405                for (; it.hasNext();) {
406                    values[index++] = it.next();
407                }
408                return new SpreadList(values);
409            }
410            else {
411                throw new SpreadListEvaluatingException("Cannot spread the type " + value.getClass().getName() + ", value " + value);
412            }
413        }
414    
415        public static SpreadMap spreadMap(Object value) {
416            if (value instanceof Map) {
417                Object[] values = new Object[((Map) value).keySet().size() * 2];
418                int index = 0;
419                Iterator it = ((Map) value).keySet().iterator();
420                for (; it.hasNext();) {
421                    Object key = it.next();
422                    values[index++] = key;
423                    values[index++] = ((Map) value).get(key);
424                }
425                return new SpreadMap(values);
426            }
427            else {
428                throw new SpreadMapEvaluatingException("Cannot spread the map " + value.getClass().getName() + ", value " + value);
429            }
430        }
431    
432        public static List createList(Object[] values) {
433            ArrayList answer = new ArrayList(values.length);
434            for (int i = 0; i < values.length; i++) {
435                if (values[i] instanceof SpreadList) {
436                    SpreadList slist = (SpreadList) values[i];
437                    for (int j = 0; j < slist.size(); j++) {
438                        answer.add(slist.get(j));
439                    }
440                }
441                else {
442                    answer.add(values[i]);
443                }
444            }
445            return answer;
446        }
447    
448        public static Map createMap(Object[] values) {
449            Map answer = new HashMap(values.length / 2);
450            int i = 0;
451            while (i < values.length - 1) {
452                if ((values[i] instanceof SpreadMap) && (values[i+1] instanceof Map)) {
453                    Map smap = (Map) values[i+1];
454                    Iterator iter = smap.keySet().iterator();
455                    for (; iter.hasNext(); ) {
456                        Object key = (Object) iter.next();
457                        answer.put(key, smap.get(key));
458                    }
459                    i+=2;
460                }
461                else {
462                    answer.put(values[i++], values[i++]);
463                }
464            }
465            return answer;
466        }
467    
468        public static List createRange(Object from, Object to, boolean inclusive) {
469            if (!inclusive) {
470                if (compareEqual(from,to)){
471                    return new EmptyRange((Comparable)from);
472                }
473                if (compareGreaterThan(from, to)) {
474                    to = invokeMethod(to, "next", EMPTY_ARGS);
475                }
476                else {
477                    to = invokeMethod(to, "previous", EMPTY_ARGS);
478                }
479            }
480            if (from instanceof Integer && to instanceof Integer) {
481                return new IntRange(asInt(from), asInt(to));
482            }
483            else {
484                return new ObjectRange((Comparable) from, (Comparable) to);
485            }
486        }
487    
488        public static int asInt(Object value) {
489            return getInstance().asInt(value);
490        }
491    
492        public static void assertFailed(Object expression, Object message) {
493            if (message == null || "".equals(message)) {
494                throw new AssertionError("Expression: " + expression);
495            }
496            else {
497                throw new AssertionError("" + message + ". Expression: " + expression);
498            }
499        }
500    
501        public static Object runScript(Class scriptClass, String[] args) {
502            Binding context = new Binding(args);
503            Script script = createScript(scriptClass, context);
504            return invokeMethod(script, "run", EMPTY_ARGS);
505        }
506    
507        public static Script createScript(Class scriptClass, Binding context) {
508            // for empty scripts
509            if (scriptClass == null) {
510                return new Script() {
511                    public Object run() {
512                        return null;
513                    }
514                };
515            }
516            try {
517                final GroovyObject object = (GroovyObject) scriptClass.newInstance();
518                Script script = null;
519                if (object instanceof Script) {
520                    script = (Script) object;
521                }
522                else {
523                    // it could just be a class, so lets wrap it in a Script wrapper
524                    // though the bindings will be ignored
525                    script = new Script() {
526                        public Object run() {
527                            object.invokeMethod("main", EMPTY_MAIN_ARGS);
528                            return null;
529                        }
530                    };
531                    setProperties(object, context.getVariables());
532                }
533                script.setBinding(context);
534                return script;
535            }
536            catch (Exception e) {
537                throw new GroovyRuntimeException("Failed to create Script instance for class: " + scriptClass + ". Reason: " + e,
538                        e);
539            }
540        }
541    
542        /**
543         * Sets the properties on the given object
544         *
545         * @param object
546         * @param map
547         */
548        public static void setProperties(Object object, Map map) {
549            getMetaClass(object).setProperties(object, map);
550        }
551    
552        public static String getVersion() {
553            String version = null;
554            Package p = Package.getPackage("groovy.lang");
555            if (p != null) {
556                version = p.getImplementationVersion();
557            }
558            if (version == null) {
559                version = "";
560            }
561            return version;
562        }
563    
564        /**
565         * Allows conversion of arrays into a mutable List
566         *
567         * @return the array as a List
568         */
569        protected static List primitiveArrayToList(Object array) {
570            int size = Array.getLength(array);
571            List list = new ArrayList(size);
572            for (int i = 0; i < size; i++) {
573                list.add(Array.get(array, i));
574            }
575            return list;
576        }
577    
578        /**
579         * Writes the given object to the given stream
580         */
581        public static void write(Writer out, Object object) throws IOException {
582            if (object instanceof String) {
583                out.write((String) object);
584            }
585            else if (object instanceof Object[]) {
586                out.write(toArrayString((Object[]) object));
587            }
588            else if (object instanceof Map) {
589                out.write(toMapString((Map) object));
590            }
591            else if (object instanceof Collection) {
592                out.write(toListString((Collection) object));
593            }
594            else if (object instanceof Writable) {
595                Writable writable = (Writable) object;
596                writable.writeTo(out);
597            }
598            else if (object instanceof InputStream || object instanceof Reader) {
599                // Copy stream to stream
600                Reader reader;
601                if (object instanceof InputStream) {
602                    reader = new InputStreamReader((InputStream) object);
603                }
604                else {
605                    reader = (Reader) object;
606                }
607                char[] chars = new char[8192];
608                int i;
609                while ((i = reader.read(chars)) != -1) {
610                    out.write(chars, 0, i);
611                }
612                reader.close();
613            }
614            else {
615                out.write(toString(object));
616            }
617        }
618    
619        public static Object box(boolean value) {
620            return value ? Boolean.TRUE : Boolean.FALSE;
621        }
622    
623        public static Object box(byte value) {
624            return new Byte(value);
625        }
626    
627        public static Object box(char value) {
628            return new Character(value);
629        }
630    
631        public static Object box(short value) {
632            return new Short(value);
633        }
634    
635        public static Object box(int value) {
636            return integerValue(value);
637        }
638    
639        public static Object box(long value) {
640            return new Long(value);
641        }
642    
643        public static Object box(float value) {
644            return new Float(value);
645        }
646    
647        public static Object box(double value) {
648            return new Double(value);
649        }
650    
651        public static byte byteUnbox(Object value) {
652            Number n = (Number) asType(value, Byte.class);
653            return n.byteValue();
654        }
655    
656        public static char charUnbox(Object value) {
657            Character n = (Character) asType(value, Character.class);
658            return n.charValue();
659        }
660    
661        public static short shortUnbox(Object value) {
662            Number n = (Number) asType(value, Short.class);
663            return n.shortValue();
664        }
665    
666        public static int intUnbox(Object value) {
667            Number n = (Number) asType(value, Integer.class);
668            return n.intValue();
669        }
670    
671        public static boolean booleanUnbox(Object value) {
672            Boolean n = (Boolean) asType(value, Boolean.class);
673            return n.booleanValue();
674        }
675    
676        public static long longUnbox(Object value) {
677            Number n = (Number) asType(value, Long.class);
678            return n.longValue();
679        }
680    
681        public static float floatUnbox(Object value) {
682            Number n = (Number) asType(value, Float.class);
683            return n.floatValue();
684        }
685    
686        public static double doubleUnbox(Object value) {
687            Number n = (Number) asType(value, Double.class);
688            return n.doubleValue();
689        }
690    
691        /**
692         * @param a    array of primitives
693         * @param type component type of the array
694         * @return
695         */
696        public static Object[] convertPrimitiveArray(Object a, Class type) {
697    //        System.out.println("a.getClass() = " + a.getClass());
698            Object[] ans = null;
699            String elemType = type.getName();
700            if (elemType.equals("int")) {
701                // conservative coding
702                if (a.getClass().getName().equals("[Ljava.lang.Integer;")) {
703                    ans = (Integer[]) a;
704                }
705                else {
706                    int[] ia = (int[]) a;
707                    ans = new Integer[ia.length];
708                    for (int i = 0; i < ia.length; i++) {
709                        int e = ia[i];
710                        ans[i] = integerValue(e);
711                    }
712                }
713            }
714            else if (elemType.equals("char")) {
715                if (a.getClass().getName().equals("[Ljava.lang.Character;")) {
716                    ans = (Character[]) a;
717                }
718                else {
719                    char[] ia = (char[]) a;
720                    ans = new Character[ia.length];
721                    for (int i = 0; i < ia.length; i++) {
722                        char e = ia[i];
723                        ans[i] = new Character(e);
724                    }
725                }
726            }
727            else if (elemType.equals("boolean")) {
728                if (a.getClass().getName().equals("[Ljava.lang.Boolean;")) {
729                    ans = (Boolean[]) a;
730                }
731                else {
732                    boolean[] ia = (boolean[]) a;
733                    ans = new Boolean[ia.length];
734                    for (int i = 0; i < ia.length; i++) {
735                        boolean e = ia[i];
736                        ans[i] = new Boolean(e);
737                    }
738                }
739            }
740            else if (elemType.equals("byte")) {
741                if (a.getClass().getName().equals("[Ljava.lang.Byte;")) {
742                    ans = (Byte[]) a;
743                }
744                else {
745                    byte[] ia = (byte[]) a;
746                    ans = new Byte[ia.length];
747                    for (int i = 0; i < ia.length; i++) {
748                        byte e = ia[i];
749                        ans[i] = new Byte(e);
750                    }
751                }
752            }
753            else if (elemType.equals("short")) {
754                if (a.getClass().getName().equals("[Ljava.lang.Short;")) {
755                    ans = (Short[]) a;
756                }
757                else {
758                    short[] ia = (short[]) a;
759                    ans = new Short[ia.length];
760                    for (int i = 0; i < ia.length; i++) {
761                        short e = ia[i];
762                        ans[i] = new Short(e);
763                    }
764                }
765            }
766            else if (elemType.equals("float")) {
767                if (a.getClass().getName().equals("[Ljava.lang.Float;")) {
768                    ans = (Float[]) a;
769                }
770                else {
771                    float[] ia = (float[]) a;
772                    ans = new Float[ia.length];
773                    for (int i = 0; i < ia.length; i++) {
774                        float e = ia[i];
775                        ans[i] = new Float(e);
776                    }
777                }
778            }
779            else if (elemType.equals("long")) {
780                if (a.getClass().getName().equals("[Ljava.lang.Long;")) {
781                    ans = (Long[]) a;
782                }
783                else {
784                    long[] ia = (long[]) a;
785                    ans = new Long[ia.length];
786                    for (int i = 0; i < ia.length; i++) {
787                        long e = ia[i];
788                        ans[i] = new Long(e);
789                    }
790                }
791            }
792            else if (elemType.equals("double")) {
793                if (a.getClass().getName().equals("[Ljava.lang.Double;")) {
794                    ans = (Double[]) a;
795                }
796                else {
797                    double[] ia = (double[]) a;
798                    ans = new Double[ia.length];
799                    for (int i = 0; i < ia.length; i++) {
800                        double e = ia[i];
801                        ans[i] = new Double(e);
802                    }
803                }
804            }
805            return ans;
806        }
807    
808        public static int[] convertToIntArray(Object a) {
809            int[] ans = null;
810    
811            // conservative coding
812            if (a.getClass().getName().equals("[I")) {
813                ans = (int[]) a;
814            }
815            else {
816                Object[] ia = (Object[]) a;
817                ans = new int[ia.length];
818                for (int i = 0; i < ia.length; i++) {
819                    if (ia[i] == null) {
820                        continue;
821                    }
822                    ans[i] = ((Number) ia[i]).intValue();
823                }
824            }
825            return ans;
826        }
827    
828        public static boolean[] convertToBooleanArray(Object a) {
829            boolean[] ans = null;
830    
831            // conservative coding
832            if (a.getClass().getName().equals("[Z")) {
833                ans = (boolean[]) a;
834            }
835            else {
836                Object[] ia = (Object[]) a;
837                ans = new boolean[ia.length];
838                for (int i = 0; i < ia.length; i++) {
839                    if (ia[i] == null) {
840                        continue;
841                    }
842                    ans[i] = ((Boolean) ia[i]).booleanValue();
843                }
844            }
845            return ans;
846        }
847    
848        public static byte[] convertToByteArray(Object a) {
849            byte[] ans = null;
850    
851            // conservative coding
852            if (a.getClass().getName().equals("[B")) {
853                ans = (byte[]) a;
854            }
855            else {
856                Object[] ia = (Object[]) a;
857                ans = new byte[ia.length];
858                for (int i = 0; i < ia.length; i++) {
859                    if (ia[i] != null) {
860                        ans[i] = ((Number) ia[i]).byteValue();
861                    }
862                }
863            }
864            return ans;
865        }
866    
867        public static short[] convertToShortArray(Object a) {
868            short[] ans = null;
869    
870            // conservative coding
871            if (a.getClass().getName().equals("[S")) {
872                ans = (short[]) a;
873            }
874            else {
875                Object[] ia = (Object[]) a;
876                ans = new short[ia.length];
877                for (int i = 0; i < ia.length; i++) {
878                    ans[i] = ((Number) ia[i]).shortValue();
879                }
880            }
881            return ans;
882        }
883    
884        public static char[] convertToCharArray(Object a) {
885            char[] ans = null;
886    
887            // conservative coding
888            if (a.getClass().getName().equals("[C")) {
889                ans = (char[]) a;
890            }
891            else {
892                Object[] ia = (Object[]) a;
893                ans = new char[ia.length];
894                for (int i = 0; i < ia.length; i++) {
895                    if (ia[i] == null) {
896                        continue;
897                    }
898                    ans[i] = ((Character) ia[i]).charValue();
899                }
900            }
901            return ans;
902        }
903    
904        public static long[] convertToLongArray(Object a) {
905            long[] ans = null;
906    
907            // conservative coding
908            if (a.getClass().getName().equals("[J")) {
909                ans = (long[]) a;
910            }
911            else {
912                Object[] ia = (Object[]) a;
913                ans = new long[ia.length];
914                for (int i = 0; i < ia.length; i++) {
915                    if (ia[i] == null) {
916                        continue;
917                    }
918                    ans[i] = ((Number) ia[i]).longValue();
919                }
920            }
921            return ans;
922        }
923    
924        public static float[] convertToFloatArray(Object a) {
925            float[] ans = null;
926    
927            // conservative coding
928            if (a.getClass().getName().equals("[F")) {
929                ans = (float[]) a;
930            }
931            else {
932                Object[] ia = (Object[]) a;
933                ans = new float[ia.length];
934                for (int i = 0; i < ia.length; i++) {
935                    if (ia[i] == null) {
936                        continue;
937                    }
938                    ans[i] = ((Number) ia[i]).floatValue();
939                }
940            }
941            return ans;
942        }
943    
944        public static double[] convertToDoubleArray(Object a) {
945            double[] ans = null;
946    
947            // conservative coding
948            if (a.getClass().getName().equals("[D")) {
949                ans = (double[]) a;
950            }
951            else {
952                Object[] ia = (Object[]) a;
953                ans = new double[ia.length];
954                for (int i = 0; i < ia.length; i++) {
955                    if (ia[i] == null) {
956                        continue;
957                    }
958                    ans[i] = ((Number) ia[i]).doubleValue();
959                }
960            }
961            return ans;
962        }
963    
964        public static Object convertToPrimitiveArray(Object a, Class type) {
965            if (type == Byte.TYPE) {
966                return convertToByteArray(a);
967            }
968            if (type == Boolean.TYPE) {
969                return convertToBooleanArray(a);
970            }
971            if (type == Short.TYPE) {
972                return convertToShortArray(a);
973            }
974            if (type == Character.TYPE) {
975                return convertToCharArray(a);
976            }
977            if (type == Integer.TYPE) {
978                return convertToIntArray(a);
979            }
980            if (type == Long.TYPE) {
981                return convertToLongArray(a);
982            }
983            if (type == Float.TYPE) {
984                return convertToFloatArray(a);
985            }
986            if (type == Double.TYPE) {
987                return convertToDoubleArray(a);
988            }
989            else {
990                return a;
991            }
992        }
993    
994        /**
995         * get the Integer object from an int. Cached version is used for small ints.
996         *
997         * @param v
998         * @return
999         */
1000        public static Integer integerValue(int v) {
1001            int index = v + INT_CACHE_OFFSET;
1002            if (index >= 0 && index < INT_CACHE_LEN) {
1003                return SMALL_INTEGERS[index];
1004            }
1005            else {
1006                return new Integer(v);
1007            }
1008        }
1009    
1010        private static Integer[] SMALL_INTEGERS;
1011        private static int INT_CACHE_OFFSET = 128, INT_CACHE_LEN = 256;
1012    
1013        static {
1014            SMALL_INTEGERS = new Integer[INT_CACHE_LEN];
1015            for (int i = 0; i < SMALL_INTEGERS.length; i++) {
1016                SMALL_INTEGERS[i] = new Integer(i - INT_CACHE_OFFSET);
1017            }
1018        }
1019    }