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