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