Source Code Cross Referenced for MetaClassHelper.java in  » Scripting » groovy-1.0 » org » codehaus » groovy » runtime » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » groovy 1.0 » org.codehaus.groovy.runtime 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2005 John G. Wilson
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *     http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         *
0016:         */
0017:
0018:        package org.codehaus.groovy.runtime;
0019:
0020:        import groovy.lang.Closure;
0021:        import groovy.lang.GString;
0022:        import groovy.lang.GroovyRuntimeException;
0023:        import groovy.lang.MetaMethod;
0024:
0025:        import java.lang.reflect.Array;
0026:        import java.lang.reflect.Constructor;
0027:        import java.lang.reflect.InvocationHandler;
0028:        import java.lang.reflect.InvocationTargetException;
0029:        import java.lang.reflect.Method;
0030:        import java.lang.reflect.Modifier;
0031:        import java.lang.reflect.Proxy;
0032:        import java.math.BigDecimal;
0033:        import java.math.BigInteger;
0034:        import java.util.Iterator;
0035:        import java.util.List;
0036:        import java.util.logging.Level;
0037:        import java.util.logging.Logger;
0038:
0039:        import org.codehaus.groovy.GroovyBugError;
0040:        import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
0041:        import org.codehaus.groovy.runtime.wrappers.Wrapper;
0042:
0043:        /**
0044:         * @author John Wilson
0045:         * @author Jochen Theodorou
0046:         */
0047:        public class MetaClassHelper {
0048:
0049:            public static final Object[] EMPTY_ARRAY = {};
0050:            public static Class[] EMPTY_TYPE_ARRAY = {};
0051:            protected static final Object[] ARRAY_WITH_NULL = { null };
0052:            protected static final Logger log = Logger
0053:                    .getLogger(MetaClassHelper.class.getName());
0054:            private static final int MAX_ARG_LEN = 12;
0055:
0056:            public static boolean accessibleToConstructor(final Class at,
0057:                    final Constructor constructor) {
0058:                boolean accessible = false;
0059:                if (Modifier.isPublic(constructor.getModifiers())) {
0060:                    accessible = true;
0061:                } else if (Modifier.isPrivate(constructor.getModifiers())) {
0062:                    accessible = at.getName().equals(constructor.getName());
0063:                } else if (Modifier.isProtected(constructor.getModifiers())) {
0064:                    if (at.getPackage() == null
0065:                            && constructor.getDeclaringClass().getPackage() == null) {
0066:                        accessible = true;
0067:                    } else if (at.getPackage() == null
0068:                            && constructor.getDeclaringClass().getPackage() != null) {
0069:                        accessible = false;
0070:                    } else if (at.getPackage() != null
0071:                            && constructor.getDeclaringClass().getPackage() == null) {
0072:                        accessible = false;
0073:                    } else if (at.getPackage().equals(
0074:                            constructor.getDeclaringClass().getPackage())) {
0075:                        accessible = true;
0076:                    } else {
0077:                        boolean flag = false;
0078:                        Class clazz = at;
0079:                        while (!flag && clazz != null) {
0080:                            if (clazz.equals(constructor.getDeclaringClass())) {
0081:                                flag = true;
0082:                                break;
0083:                            }
0084:                            if (clazz.equals(Object.class)) {
0085:                                break;
0086:                            }
0087:                            clazz = clazz.getSuperclass();
0088:                        }
0089:                        accessible = flag;
0090:                    }
0091:                } else {
0092:                    if (at.getPackage() == null
0093:                            && constructor.getDeclaringClass().getPackage() == null) {
0094:                        accessible = true;
0095:                    } else if (at.getPackage() == null
0096:                            && constructor.getDeclaringClass().getPackage() != null) {
0097:                        accessible = false;
0098:                    } else if (at.getPackage() != null
0099:                            && constructor.getDeclaringClass().getPackage() == null) {
0100:                        accessible = false;
0101:                    } else if (at.getPackage().equals(
0102:                            constructor.getDeclaringClass().getPackage())) {
0103:                        accessible = true;
0104:                    }
0105:                }
0106:                return accessible;
0107:            }
0108:
0109:            public static Object[] asWrapperArray(Object parameters,
0110:                    Class componentType) {
0111:                Object[] ret = null;
0112:                if (componentType == boolean.class) {
0113:                    boolean[] array = (boolean[]) parameters;
0114:                    ret = new Object[array.length];
0115:                    for (int i = 0; i < array.length; i++) {
0116:                        ret[i] = new Boolean(array[i]);
0117:                    }
0118:                } else if (componentType == char.class) {
0119:                    char[] array = (char[]) parameters;
0120:                    ret = new Object[array.length];
0121:                    for (int i = 0; i < array.length; i++) {
0122:                        ret[i] = new Character(array[i]);
0123:                    }
0124:                } else if (componentType == byte.class) {
0125:                    byte[] array = (byte[]) parameters;
0126:                    ret = new Object[array.length];
0127:                    for (int i = 0; i < array.length; i++) {
0128:                        ret[i] = new Byte(array[i]);
0129:                    }
0130:                } else if (componentType == int.class) {
0131:                    int[] array = (int[]) parameters;
0132:                    ret = new Object[array.length];
0133:                    for (int i = 0; i < array.length; i++) {
0134:                        ret[i] = new Integer(array[i]);
0135:                    }
0136:                } else if (componentType == short.class) {
0137:                    short[] array = (short[]) parameters;
0138:                    ret = new Object[array.length];
0139:                    for (int i = 0; i < array.length; i++) {
0140:                        ret[i] = new Short(array[i]);
0141:                    }
0142:                } else if (componentType == long.class) {
0143:                    long[] array = (long[]) parameters;
0144:                    ret = new Object[array.length];
0145:                    for (int i = 0; i < array.length; i++) {
0146:                        ret[i] = new Long(array[i]);
0147:                    }
0148:                } else if (componentType == double.class) {
0149:                    double[] array = (double[]) parameters;
0150:                    ret = new Object[array.length];
0151:                    for (int i = 0; i < array.length; i++) {
0152:                        ret[i] = new Double(array[i]);
0153:                    }
0154:                } else if (componentType == float.class) {
0155:                    float[] array = (float[]) parameters;
0156:                    ret = new Object[array.length];
0157:                    for (int i = 0; i < array.length; i++) {
0158:                        ret[i] = new Float(array[i]);
0159:                    }
0160:                }
0161:
0162:                return ret;
0163:            }
0164:
0165:            /**
0166:             * @param list
0167:             * @param parameterType
0168:             */
0169:            public static Object asPrimitiveArray(List list, Class parameterType) {
0170:                Class arrayType = parameterType.getComponentType();
0171:                Object objArray = Array.newInstance(arrayType, list.size());
0172:                for (int i = 0; i < list.size(); i++) {
0173:                    Object obj = list.get(i);
0174:                    if (arrayType.isPrimitive()) {
0175:                        if (obj instanceof  Integer) {
0176:                            Array.setInt(objArray, i, ((Integer) obj)
0177:                                    .intValue());
0178:                        } else if (obj instanceof  Double) {
0179:                            Array.setDouble(objArray, i, ((Double) obj)
0180:                                    .doubleValue());
0181:                        } else if (obj instanceof  Boolean) {
0182:                            Array.setBoolean(objArray, i, ((Boolean) obj)
0183:                                    .booleanValue());
0184:                        } else if (obj instanceof  Long) {
0185:                            Array
0186:                                    .setLong(objArray, i, ((Long) obj)
0187:                                            .longValue());
0188:                        } else if (obj instanceof  Float) {
0189:                            Array.setFloat(objArray, i, ((Float) obj)
0190:                                    .floatValue());
0191:                        } else if (obj instanceof  Character) {
0192:                            Array.setChar(objArray, i, ((Character) obj)
0193:                                    .charValue());
0194:                        } else if (obj instanceof  Byte) {
0195:                            Array
0196:                                    .setByte(objArray, i, ((Byte) obj)
0197:                                            .byteValue());
0198:                        } else if (obj instanceof  Short) {
0199:                            Array.setShort(objArray, i, ((Short) obj)
0200:                                    .shortValue());
0201:                        }
0202:                    } else {
0203:                        Array.set(objArray, i, obj);
0204:                    }
0205:                }
0206:                return objArray;
0207:            }
0208:
0209:            protected static Class autoboxType(Class type) {
0210:                if (type.isPrimitive()) {
0211:                    if (type == int.class) {
0212:                        return Integer.class;
0213:                    } else if (type == double.class) {
0214:                        return Double.class;
0215:                    } else if (type == long.class) {
0216:                        return Long.class;
0217:                    } else if (type == boolean.class) {
0218:                        return Boolean.class;
0219:                    } else if (type == float.class) {
0220:                        return Float.class;
0221:                    } else if (type == char.class) {
0222:                        return Character.class;
0223:                    } else if (type == byte.class) {
0224:                        return Byte.class;
0225:                    } else if (type == short.class) {
0226:                        return Short.class;
0227:                    }
0228:                }
0229:                return type;
0230:            }
0231:
0232:            private static Class[] primitives = { byte.class, Byte.class,
0233:                    short.class, Short.class, int.class, Integer.class,
0234:                    long.class, Long.class, BigInteger.class, float.class,
0235:                    Float.class, double.class, Double.class, BigDecimal.class,
0236:                    Number.class, Object.class };
0237:            private static int[][] primitiveDistanceTable = {
0238:                    //              byte    Byte    short   Short   int     Integer     long    Long    BigInteger  float   Float   double  Double  BigDecimal, Number, Object 
0239:                    /* byte*/{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
0240:                            14, 15, },
0241:                    /*Byte*/{ 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
0242:                            14, 15, },
0243:                    /*short*/{ 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
0244:                            12, 13, },
0245:                    /*Short*/{ 14, 15, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
0246:                            12, 13, },
0247:                    /*int*/{ 14, 15, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
0248:                            11, },
0249:                    /*Integer*/{ 14, 15, 12, 13, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9,
0250:                            10, 11, },
0251:                    /*long*/{ 14, 15, 12, 13, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7,
0252:                            8, 9, },
0253:                    /*Long*/{ 14, 15, 12, 13, 10, 11, 1, 0, 2, 3, 4, 5, 6, 7,
0254:                            8, 9, },
0255:                    /*BigInteger*/{ 14, 15, 12, 13, 10, 11, 8, 9, 0, 1, 2, 3,
0256:                            4, 5, 6, 7, },
0257:                    /*float*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 0, 1, 2, 3, 4,
0258:                            5, 6, },
0259:                    /*Float*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 1, 0, 2, 3, 4,
0260:                            5, 6, },
0261:                    /*double*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 0, 1,
0262:                            2, 3, 4, },
0263:                    /*Double*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 1, 0,
0264:                            2, 3, 4, },
0265:                    /*BigDecimal*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 3,
0266:                            4, 0, 1, 2, },
0267:                    /*Numer*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 3, 4, 2,
0268:                            0, 1, },
0269:                    /*Object*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 3, 4,
0270:                            2, 1, 0, }, };
0271:
0272:            private static int getPrimitiveIndex(Class c) {
0273:                for (byte i = 0; i < primitives.length; i++) {
0274:                    if (primitives[i] == c)
0275:                        return i;
0276:                }
0277:                return -1;
0278:            }
0279:
0280:            private static int getPrimitiveDistance(Class from, Class to) {
0281:                // we know here that from!=to, so a distance of 0 is never valid
0282:                // get primitive type indexes
0283:                int fromIndex = getPrimitiveIndex(from);
0284:                int toIndex = getPrimitiveIndex(to);
0285:                if (fromIndex == -1 || toIndex == -1)
0286:                    return -1;
0287:                return primitiveDistanceTable[toIndex][fromIndex];
0288:            }
0289:
0290:            private static int getMaximumInterfaceDistance(Class c,
0291:                    Class interfaceClass) {
0292:                if (c == interfaceClass)
0293:                    return 0;
0294:                Class[] interfaces = c.getInterfaces();
0295:                int max = 0;
0296:                for (int i = 0; i < interfaces.length; i++) {
0297:                    int sub = 0;
0298:                    if (interfaces[i].isAssignableFrom(c)) {
0299:                        sub = 1 + getMaximumInterfaceDistance(interfaces[i],
0300:                                interfaceClass);
0301:                    }
0302:                    max = Math.max(max, sub);
0303:                }
0304:                return max;
0305:            }
0306:
0307:            public static long calculateParameterDistance(Class[] arguments,
0308:                    Class[] parameters) {
0309:                int objectDistance = 0, interfaceDistance = 0;
0310:                for (int i = 0; i < arguments.length; i++) {
0311:                    if (parameters[i] == arguments[i])
0312:                        continue;
0313:
0314:                    if (parameters[i].isInterface()) {
0315:                        objectDistance += primitives.length;
0316:                        interfaceDistance += getMaximumInterfaceDistance(
0317:                                arguments[i], parameters[i]);
0318:                        continue;
0319:                    }
0320:
0321:                    if (arguments[i] != null) {
0322:                        int pd = getPrimitiveDistance(parameters[i],
0323:                                arguments[i]);
0324:                        if (pd != -1) {
0325:                            objectDistance += pd;
0326:                            continue;
0327:                        }
0328:
0329:                        // add one to dist to be sure interfaces are prefered
0330:                        objectDistance += primitives.length + 1;
0331:                        Class clazz = autoboxType(arguments[i]);
0332:                        while (clazz != null) {
0333:                            if (clazz == parameters[i])
0334:                                break;
0335:                            if (clazz == GString.class
0336:                                    && parameters[i] == String.class) {
0337:                                objectDistance += 2;
0338:                                break;
0339:                            }
0340:                            clazz = clazz.getSuperclass();
0341:                            objectDistance += 3;
0342:                        }
0343:                    } else {
0344:                        // choose the distance to Object if a parameter is null
0345:                        // this will mean that Object is prefered over a more
0346:                        // specific type
0347:                        // remove one to dist to be sure Object is prefered
0348:                        objectDistance--;
0349:                        Class clazz = parameters[i];
0350:                        if (clazz.isPrimitive()) {
0351:                            objectDistance += 2;
0352:                        } else {
0353:                            while (clazz != Object.class) {
0354:                                clazz = clazz.getSuperclass();
0355:                                objectDistance += 2;
0356:                            }
0357:                        }
0358:                    }
0359:                }
0360:                long ret = objectDistance;
0361:                ret <<= 32;
0362:                ret |= interfaceDistance;
0363:                return ret;
0364:            }
0365:
0366:            public static String capitalize(String property) {
0367:                return property.substring(0, 1).toUpperCase()
0368:                        + property.substring(1, property.length());
0369:            }
0370:
0371:            /**
0372:             * @return the method with 1 parameter which takes the most general type of
0373:             *         object (e.g. Object)
0374:             */
0375:            public static Object chooseEmptyMethodParams(List methods) {
0376:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
0377:                    Object method = iter.next();
0378:                    Class[] paramTypes = getParameterTypes(method);
0379:                    int paramLength = paramTypes.length;
0380:                    if (paramLength == 0) {
0381:                        return method;
0382:                    }
0383:                }
0384:                return null;
0385:            }
0386:
0387:            /**
0388:             * @return the method with 1 parameter which takes the most general type of
0389:             *         object (e.g. Object) ignoring primitve types
0390:             */
0391:            public static Object chooseMostGeneralMethodWith1NullParam(
0392:                    List methods) {
0393:                // lets look for methods with 1 argument which matches the type of the
0394:                // arguments
0395:                Class closestClass = null;
0396:                Object answer = null;
0397:
0398:                for (Iterator iter = methods.iterator(); iter.hasNext();) {
0399:                    Object method = iter.next();
0400:                    Class[] paramTypes = getParameterTypes(method);
0401:                    int paramLength = paramTypes.length;
0402:                    if (paramLength == 1) {
0403:                        Class theType = paramTypes[0];
0404:                        if (theType.isPrimitive())
0405:                            continue;
0406:                        if (closestClass == null
0407:                                || isAssignableFrom(theType, closestClass)) {
0408:                            closestClass = theType;
0409:                            answer = method;
0410:                        }
0411:                    }
0412:                }
0413:                return answer;
0414:            }
0415:
0416:            /**
0417:             * Coerces a GString instance into String if needed
0418:             *
0419:             * @return the coerced argument
0420:             */
0421:            protected static Object coerceGString(Object argument, Class clazz) {
0422:                if (clazz != String.class)
0423:                    return argument;
0424:                if (!(argument instanceof  GString))
0425:                    return argument;
0426:                return argument.toString();
0427:            }
0428:
0429:            protected static Object coerceNumber(Object argument, Class param) {
0430:                if ((Number.class.isAssignableFrom(param) || param
0431:                        .isPrimitive())
0432:                        && argument instanceof  Number) { // Number types
0433:                    Object oldArgument = argument;
0434:                    boolean wasDouble = false;
0435:                    boolean wasFloat = false;
0436:                    if (param == Byte.class || param == Byte.TYPE) {
0437:                        argument = new Byte(((Number) argument).byteValue());
0438:                    } else if (param == Double.class || param == Double.TYPE) {
0439:                        wasDouble = true;
0440:                        argument = new Double(((Number) argument).doubleValue());
0441:                    } else if (param == Float.class || param == Float.TYPE) {
0442:                        wasFloat = true;
0443:                        argument = new Float(((Number) argument).floatValue());
0444:                    } else if (param == Integer.class || param == Integer.TYPE) {
0445:                        argument = new Integer(((Number) argument).intValue());
0446:                    } else if (param == Long.class || param == Long.TYPE) {
0447:                        argument = new Long(((Number) argument).longValue());
0448:                    } else if (param == Short.class || param == Short.TYPE) {
0449:                        argument = new Short(((Number) argument).shortValue());
0450:                    } else if (param == BigDecimal.class) {
0451:                        argument = new BigDecimal(String
0452:                                .valueOf((Number) argument));
0453:                    } else if (param == BigInteger.class) {
0454:                        argument = new BigInteger(String
0455:                                .valueOf((Number) argument));
0456:                    }
0457:
0458:                    if (oldArgument instanceof  BigDecimal) {
0459:                        BigDecimal oldbd = (BigDecimal) oldArgument;
0460:                        boolean throwException = false;
0461:                        if (wasDouble) {
0462:                            Double d = (Double) argument;
0463:                            if (d.isInfinite())
0464:                                throwException = true;
0465:                        } else if (wasFloat) {
0466:                            Float f = (Float) argument;
0467:                            if (f.isInfinite())
0468:                                throwException = true;
0469:                        } else {
0470:                            BigDecimal newbd = new BigDecimal(String
0471:                                    .valueOf((Number) argument));
0472:                            throwException = !oldArgument.equals(newbd);
0473:                        }
0474:
0475:                        if (throwException)
0476:                            throw new IllegalArgumentException(
0477:                                    param
0478:                                            + " out of range while converting from BigDecimal");
0479:                    }
0480:
0481:                }
0482:                return argument;
0483:            }
0484:
0485:            protected static Object coerceArray(Object argument, Class param) {
0486:                if (!param.isArray())
0487:                    return argument;
0488:                Class argumentClass = argument.getClass();
0489:                if (!argumentClass.isArray())
0490:                    return argument;
0491:
0492:                Class paramComponent = param.getComponentType();
0493:                if (paramComponent.isPrimitive()) {
0494:                    if (paramComponent == boolean.class
0495:                            && argumentClass == Boolean[].class) {
0496:                        argument = DefaultTypeTransformation
0497:                                .convertToBooleanArray(argument);
0498:                    } else if (paramComponent == byte.class
0499:                            && argumentClass == Byte[].class) {
0500:                        argument = DefaultTypeTransformation
0501:                                .convertToByteArray(argument);
0502:                    } else if (paramComponent == char.class
0503:                            && argumentClass == Character[].class) {
0504:                        argument = DefaultTypeTransformation
0505:                                .convertToCharArray(argument);
0506:                    } else if (paramComponent == short.class
0507:                            && argumentClass == Short[].class) {
0508:                        argument = DefaultTypeTransformation
0509:                                .convertToShortArray(argument);
0510:                    } else if (paramComponent == int.class
0511:                            && argumentClass == Integer[].class) {
0512:                        argument = DefaultTypeTransformation
0513:                                .convertToIntArray(argument);
0514:                    } else if (paramComponent == long.class
0515:                            && (argumentClass == Long[].class || argumentClass == Integer[].class)) {
0516:                        argument = DefaultTypeTransformation
0517:                                .convertToLongArray(argument);
0518:                    } else if (paramComponent == float.class
0519:                            && (argumentClass == Float[].class || argumentClass == Integer[].class)) {
0520:                        argument = DefaultTypeTransformation
0521:                                .convertToFloatArray(argument);
0522:                    } else if (paramComponent == double.class
0523:                            && (argumentClass == Double[].class
0524:                                    || argumentClass == Float[].class || BigDecimal.class
0525:                                    .isAssignableFrom(argumentClass))) {
0526:                        argument = DefaultTypeTransformation
0527:                                .convertToDoubleArray(argument);
0528:                    }
0529:                } else if (paramComponent == String.class
0530:                        && argument instanceof  GString[]) {
0531:                    GString[] strings = (GString[]) argument;
0532:                    String[] ret = new String[strings.length];
0533:                    for (int i = 0; i < strings.length; i++) {
0534:                        ret[i] = strings[i].toString();
0535:                    }
0536:                    argument = ret;
0537:                }
0538:                return argument;
0539:            }
0540:
0541:            /**
0542:             * @return true if a method of the same matching prototype was found in the
0543:             *         list
0544:             */
0545:            public static boolean containsMatchingMethod(List list,
0546:                    MetaMethod method) {
0547:                for (Iterator iter = list.iterator(); iter.hasNext();) {
0548:                    MetaMethod aMethod = (MetaMethod) iter.next();
0549:                    Class[] params1 = aMethod.getParameterTypes();
0550:                    Class[] params2 = method.getParameterTypes();
0551:                    if (params1.length == params2.length) {
0552:                        boolean matches = true;
0553:                        for (int i = 0; i < params1.length; i++) {
0554:                            if (params1[i] != params2[i]) {
0555:                                matches = false;
0556:                                break;
0557:                            }
0558:                        }
0559:                        if (matches) {
0560:                            return true;
0561:                        }
0562:                    }
0563:                }
0564:                return false;
0565:            }
0566:
0567:            /**
0568:             * param instance array to the type array
0569:             * @param args
0570:             */
0571:            public static Class[] convertToTypeArray(Object[] args) {
0572:                if (args == null)
0573:                    return null;
0574:                int s = args.length;
0575:                Class[] ans = new Class[s];
0576:                for (int i = 0; i < s; i++) {
0577:                    Object o = args[i];
0578:                    if (o == null) {
0579:                        ans[i] = null;
0580:                    } else if (o instanceof  Wrapper) {
0581:                        ans[i] = ((Wrapper) o).getType();
0582:                    } else {
0583:                        ans[i] = o.getClass();
0584:                    }
0585:                }
0586:                return ans;
0587:            }
0588:
0589:            /**
0590:             * @param listenerType
0591:             *            the interface of the listener to proxy
0592:             * @param listenerMethodName
0593:             *            the name of the method in the listener API to call the
0594:             *            closure on
0595:             * @param closure
0596:             *            the closure to invoke on the listenerMethodName method
0597:             *            invocation
0598:             * @return a dynamic proxy which calls the given closure on the given
0599:             *         method name
0600:             */
0601:            public static Object createListenerProxy(Class listenerType,
0602:                    final String listenerMethodName, final Closure closure) {
0603:                InvocationHandler handler = new ClosureListener(
0604:                        listenerMethodName, closure);
0605:                return Proxy.newProxyInstance(listenerType.getClassLoader(),
0606:                        new Class[] { listenerType }, handler);
0607:            }
0608:
0609:            public static Object doConstructorInvoke(Constructor constructor,
0610:                    Object[] argumentArray) {
0611:                if (log.isLoggable(Level.FINER)) {
0612:                    logMethodCall(constructor.getDeclaringClass(), constructor
0613:                            .getName(), argumentArray);
0614:                }
0615:                argumentArray = coerceArgumentsToClasses(argumentArray,
0616:                        constructor.getParameterTypes());
0617:                try {
0618:                    return constructor.newInstance(argumentArray);
0619:                } catch (InvocationTargetException e) {
0620:                    throw new InvokerInvocationException(e);
0621:                } catch (IllegalArgumentException e) {
0622:                    throw createExceptionText("failed to invoke constructor: ",
0623:                            constructor, argumentArray, e, false);
0624:                } catch (IllegalAccessException e) {
0625:                    throw createExceptionText("could not access constructor: ",
0626:                            constructor, argumentArray, e, false);
0627:                } catch (Exception e) {
0628:                    throw createExceptionText("failed to invoke constructor: ",
0629:                            constructor, argumentArray, e, true);
0630:                }
0631:            }
0632:
0633:            private static GroovyRuntimeException createExceptionText(
0634:                    String init, Constructor constructor,
0635:                    Object[] argumentArray, Throwable e, boolean setReason) {
0636:                throw new GroovyRuntimeException(init + constructor
0637:                        + " with arguments: "
0638:                        + InvokerHelper.toString(argumentArray) + " reason: "
0639:                        + e, setReason ? e : null);
0640:            }
0641:
0642:            public static Object[] coerceArgumentsToClasses(
0643:                    Object[] argumentArray, Class[] paramTypes) {
0644:                // correct argumentArray's length
0645:                if (argumentArray == null) {
0646:                    argumentArray = EMPTY_ARRAY;
0647:                } else if (paramTypes.length == 1 && argumentArray.length == 0) {
0648:                    if (isVargsMethod(paramTypes, argumentArray))
0649:                        argumentArray = new Object[] { Array.newInstance(
0650:                                paramTypes[0].getComponentType(), 0) };
0651:                    else
0652:                        argumentArray = ARRAY_WITH_NULL;
0653:                } else if (isVargsMethod(paramTypes, argumentArray)) {
0654:                    argumentArray = fitToVargs(argumentArray, paramTypes);
0655:                }
0656:
0657:                //correct Type
0658:                for (int i = 0; i < argumentArray.length; i++) {
0659:                    Object argument = argumentArray[i];
0660:                    if (argument == null)
0661:                        continue;
0662:                    Class parameterType = paramTypes[i];
0663:                    if (parameterType.isInstance(argument))
0664:                        continue;
0665:
0666:                    argument = coerceGString(argument, parameterType);
0667:                    argument = coerceNumber(argument, parameterType);
0668:                    argument = coerceArray(argument, parameterType);
0669:                    argumentArray[i] = argument;
0670:                }
0671:                return argumentArray;
0672:            }
0673:
0674:            private static Object makeCommonArray(Object[] arguments,
0675:                    int offset, Class fallback) {
0676:                // arguments.leght>0 && !=null
0677:                Class baseClass = null;
0678:                for (int i = offset; i < arguments.length; i++) {
0679:                    if (arguments[i] == null)
0680:                        continue;
0681:                    Class argClass = arguments[i].getClass();
0682:                    if (baseClass == null) {
0683:                        baseClass = argClass;
0684:                    } else {
0685:                        for (; baseClass != Object.class; baseClass = baseClass
0686:                                .getSuperclass()) {
0687:                            if (baseClass.isAssignableFrom(argClass))
0688:                                break;
0689:                        }
0690:                    }
0691:                }
0692:                if (baseClass == null) {
0693:                    // all arguments were null
0694:                    baseClass = fallback;
0695:                }
0696:                Object result = makeArray(null, baseClass, arguments.length
0697:                        - offset);
0698:                System.arraycopy(arguments, offset, result, 0, arguments.length
0699:                        - offset);
0700:                return result;
0701:            }
0702:
0703:            private static Object makeArray(Object obj, Class secondary,
0704:                    int length) {
0705:                Class baseClass = secondary;
0706:                if (obj != null) {
0707:                    baseClass = obj.getClass();
0708:                }
0709:                /*if (GString.class.isAssignableFrom(baseClass)) {
0710:                	baseClass = GString.class;
0711:                }*/
0712:                return Array.newInstance(baseClass, length);
0713:            }
0714:
0715:            /**
0716:             * this method is called when the number of arguments to a method is greater than 1
0717:             * and if the method is a vargs method. This method will then transform the given
0718:             * arguments to make the method callable
0719:             * 
0720:             * @param argumentArray the arguments used to call the method
0721:             * @param paramTypes the types of the paramters the method takes
0722:             */
0723:            private static Object[] fitToVargs(Object[] argumentArray,
0724:                    Class[] paramTypes) {
0725:                Class vargsClass = autoboxType(paramTypes[paramTypes.length - 1]
0726:                        .getComponentType());
0727:
0728:                if (argumentArray.length == paramTypes.length - 1) {
0729:                    // the vargs argument is missing, so fill it with an empty array
0730:                    Object[] newArgs = new Object[paramTypes.length];
0731:                    System.arraycopy(argumentArray, 0, newArgs, 0,
0732:                            argumentArray.length);
0733:                    Object vargs = makeArray(null, vargsClass, 0);
0734:                    newArgs[newArgs.length - 1] = vargs;
0735:                    return newArgs;
0736:                } else if (argumentArray.length == paramTypes.length) {
0737:                    // the number of arguments is correct, but if the last argument 
0738:                    // is no array we have to wrap it in a array. if the last argument
0739:                    // is null, then we don't have to do anything
0740:                    Object lastArgument = argumentArray[argumentArray.length - 1];
0741:                    if (lastArgument != null
0742:                            && !lastArgument.getClass().isArray()) {
0743:                        // no array so wrap it
0744:                        Object vargs = makeArray(lastArgument, vargsClass, 1);
0745:                        System.arraycopy(argumentArray,
0746:                                argumentArray.length - 1, vargs, 0, 1);
0747:                        argumentArray[argumentArray.length - 1] = vargs;
0748:                        return argumentArray;
0749:                    } else {
0750:                        // we may have to box the arguemnt!
0751:                        return argumentArray;
0752:                    }
0753:                } else if (argumentArray.length > paramTypes.length) {
0754:                    // the number of arguments is too big, wrap all exceeding elements
0755:                    // in an array, but keep the old elements that are no vargs
0756:                    Object[] newArgs = new Object[paramTypes.length];
0757:                    // copy arguments that are not a varg
0758:                    System.arraycopy(argumentArray, 0, newArgs, 0,
0759:                            paramTypes.length - 1);
0760:                    // create a new array for the vargs and copy them
0761:                    int numberOfVargs = argumentArray.length
0762:                            - paramTypes.length;
0763:                    Object vargs = makeCommonArray(argumentArray,
0764:                            paramTypes.length - 1, vargsClass);
0765:                    newArgs[newArgs.length - 1] = vargs;
0766:                    return newArgs;
0767:                } else {
0768:                    throw new GroovyBugError(
0769:                            "trying to call a vargs method without enough arguments");
0770:                }
0771:            }
0772:
0773:            private static GroovyRuntimeException createExceptionText(
0774:                    String init, MetaMethod method, Object object,
0775:                    Object[] args, Throwable reason, boolean setReason) {
0776:                return new GroovyRuntimeException(init + method + " on: "
0777:                        + object + " with arguments: "
0778:                        + InvokerHelper.toString(args) + " reason: " + reason,
0779:                        setReason ? reason : null);
0780:            }
0781:
0782:            public static Object doMethodInvoke(Object object,
0783:                    MetaMethod method, Object[] argumentArray) {
0784:                Class[] paramTypes = method.getParameterTypes();
0785:                argumentArray = coerceArgumentsToClasses(argumentArray,
0786:                        paramTypes);
0787:                try {
0788:                    return method.invoke(object, argumentArray);
0789:                } catch (IllegalArgumentException e) {
0790:                    //TODO: test if this is ok with new MOP, should be changed!
0791:                    // we don't want the exception being unwrapped if it is a IllegalArgumentException
0792:                    // but in the case it is for example a IllegalThreadStateException, we want the unwrapping
0793:                    // from the runtime
0794:                    //Note: the reason we want unwrapping sometimes and sometimes not is that the method
0795:                    // invokation tries to invoke the method with and then reacts with type transformation
0796:                    // if the invokation failed here. This is ok for IllegalArgumentException, but it is
0797:                    // possible that a Reflector will be used to execute the call and then an Exception from inside
0798:                    // the method is not wrapped in a InvocationTargetException and we will end here.
0799:                    boolean setReason = e.getClass() != IllegalArgumentException.class;
0800:                    throw createExceptionText("failed to invoke method: ",
0801:                            method, object, argumentArray, e, setReason);
0802:                } catch (RuntimeException e) {
0803:                    throw e;
0804:                } catch (Exception e) {
0805:                    throw createExceptionText("failed to invoke method: ",
0806:                            method, object, argumentArray, e, true);
0807:                }
0808:            }
0809:
0810:            protected static String getClassName(Object object) {
0811:                if (object == null)
0812:                    return null;
0813:                return (object instanceof  Class) ? ((Class) object).getName()
0814:                        : object.getClass().getName();
0815:            }
0816:
0817:            /**
0818:             * Returns a callable object for the given method name on the object.
0819:             * The object acts like a Closure in that it can be called, like a closure
0820:             * and passed around - though really its a method pointer, not a closure per se.
0821:             */
0822:            public static Closure getMethodPointer(Object object,
0823:                    String methodName) {
0824:                return new MethodClosure(object, methodName);
0825:            }
0826:
0827:            public static Class[] getParameterTypes(Object methodOrConstructor) {
0828:                if (methodOrConstructor instanceof  MetaMethod) {
0829:                    MetaMethod method = (MetaMethod) methodOrConstructor;
0830:                    return method.getParameterTypes();
0831:                }
0832:                if (methodOrConstructor instanceof  Method) {
0833:                    Method method = (Method) methodOrConstructor;
0834:                    return method.getParameterTypes();
0835:                }
0836:                if (methodOrConstructor instanceof  Constructor) {
0837:                    Constructor constructor = (Constructor) methodOrConstructor;
0838:                    return constructor.getParameterTypes();
0839:                }
0840:                throw new IllegalArgumentException(
0841:                        "Must be a Method or Constructor");
0842:            }
0843:
0844:            public static boolean isAssignableFrom(Class classToTransformTo,
0845:                    Class classToTransformFrom) {
0846:                if (classToTransformFrom == null)
0847:                    return true;
0848:                classToTransformTo = autoboxType(classToTransformTo);
0849:                classToTransformFrom = autoboxType(classToTransformFrom);
0850:
0851:                if (classToTransformTo == classToTransformFrom) {
0852:                    return true;
0853:                }
0854:                // note: there is not coercion for boolean and char. Range matters, precision doesn't
0855:                else if (classToTransformTo == Integer.class) {
0856:                    if (classToTransformFrom == Integer.class
0857:                            || classToTransformFrom == Short.class
0858:                            || classToTransformFrom == Byte.class
0859:                            || classToTransformFrom == BigInteger.class)
0860:                        return true;
0861:                } else if (classToTransformTo == Double.class) {
0862:                    if (classToTransformFrom == Double.class
0863:                            || classToTransformFrom == Integer.class
0864:                            || classToTransformFrom == Long.class
0865:                            || classToTransformFrom == Short.class
0866:                            || classToTransformFrom == Byte.class
0867:                            || classToTransformFrom == Float.class
0868:                            || classToTransformFrom == BigDecimal.class
0869:                            || classToTransformFrom == BigInteger.class)
0870:                        return true;
0871:                } else if (classToTransformTo == BigDecimal.class) {
0872:                    if (classToTransformFrom == Double.class
0873:                            || classToTransformFrom == Integer.class
0874:                            || classToTransformFrom == Long.class
0875:                            || classToTransformFrom == Short.class
0876:                            || classToTransformFrom == Byte.class
0877:                            || classToTransformFrom == Float.class
0878:                            || classToTransformFrom == BigDecimal.class
0879:                            || classToTransformFrom == BigInteger.class)
0880:                        return true;
0881:                } else if (classToTransformTo == BigInteger.class) {
0882:                    if (classToTransformFrom == Integer.class
0883:                            || classToTransformFrom == Long.class
0884:                            || classToTransformFrom == Short.class
0885:                            || classToTransformFrom == Byte.class
0886:                            || classToTransformFrom == BigInteger.class)
0887:                        return true;
0888:                } else if (classToTransformTo == Long.class) {
0889:                    if (classToTransformFrom == Long.class
0890:                            || classToTransformFrom == Integer.class
0891:                            || classToTransformFrom == Short.class
0892:                            || classToTransformFrom == Byte.class)
0893:                        return true;
0894:                } else if (classToTransformTo == Float.class) {
0895:                    if (classToTransformFrom == Float.class
0896:                            || classToTransformFrom == Integer.class
0897:                            || classToTransformFrom == Long.class
0898:                            || classToTransformFrom == Short.class
0899:                            || classToTransformFrom == Byte.class)
0900:                        return true;
0901:                } else if (classToTransformTo == Short.class) {
0902:                    if (classToTransformFrom == Short.class
0903:                            || classToTransformFrom == Byte.class)
0904:                        return true;
0905:                } else if (classToTransformTo == String.class) {
0906:                    if (classToTransformFrom == String.class
0907:                            || GString.class
0908:                                    .isAssignableFrom(classToTransformFrom)) {
0909:                        return true;
0910:                    }
0911:                }
0912:
0913:                return classToTransformTo
0914:                        .isAssignableFrom(classToTransformFrom);
0915:            }
0916:
0917:            public static boolean isGenericSetMethod(MetaMethod method) {
0918:                return (method.getName().equals("set"))
0919:                        && method.getParameterTypes().length == 2;
0920:            }
0921:
0922:            protected static boolean isSuperclass(Class claszz, Class super class) {
0923:                while (claszz != null) {
0924:                    if (claszz == super class)
0925:                        return true;
0926:                    claszz = claszz.getSuperclass();
0927:                }
0928:                return false;
0929:            }
0930:
0931:            public static boolean isValidMethod(Class[] paramTypes,
0932:                    Class[] arguments, boolean includeCoerce) {
0933:                if (arguments == null) {
0934:                    return true;
0935:                }
0936:                int size = arguments.length;
0937:
0938:                if ((size >= paramTypes.length || size == paramTypes.length - 1)
0939:                        && paramTypes.length > 0
0940:                        && paramTypes[paramTypes.length - 1].isArray()) {
0941:                    // first check normal number of parameters
0942:                    for (int i = 0; i < paramTypes.length - 1; i++) {
0943:                        if (isAssignableFrom(paramTypes[i], arguments[i]))
0944:                            continue;
0945:                        return false;
0946:                    }
0947:                    // check varged
0948:                    Class clazz = paramTypes[paramTypes.length - 1]
0949:                            .getComponentType();
0950:                    for (int i = paramTypes.length; i < size; i++) {
0951:                        if (isAssignableFrom(clazz, arguments[i]))
0952:                            continue;
0953:                        return false;
0954:                    }
0955:                    return true;
0956:                } else if (paramTypes.length == size) {
0957:                    // lets check the parameter types match
0958:                    for (int i = 0; i < size; i++) {
0959:                        if (isAssignableFrom(paramTypes[i], arguments[i]))
0960:                            continue;
0961:                        return false;
0962:                    }
0963:                    return true;
0964:                } else if (paramTypes.length == 1 && size == 0) {
0965:                    return true;
0966:                }
0967:                return false;
0968:
0969:            }
0970:
0971:            public static boolean isValidMethod(Object method,
0972:                    Class[] arguments, boolean includeCoerce) {
0973:                Class[] paramTypes = getParameterTypes(method);
0974:                return isValidMethod(paramTypes, arguments, includeCoerce);
0975:            }
0976:
0977:            public static boolean isVargsMethod(Class[] paramTypes,
0978:                    Object[] arguments) {
0979:                if (paramTypes.length == 0)
0980:                    return false;
0981:                if (!paramTypes[paramTypes.length - 1].isArray())
0982:                    return false;
0983:                // -1 because the varg part is optional
0984:                if (paramTypes.length - 1 == arguments.length)
0985:                    return true;
0986:                if (paramTypes.length - 1 > arguments.length)
0987:                    return false;
0988:                if (arguments.length > paramTypes.length)
0989:                    return true;
0990:
0991:                // only case left is arguments.length==paramTypes.length
0992:                Object last = arguments[arguments.length - 1];
0993:                if (last == null)
0994:                    return true;
0995:                Class clazz = last.getClass();
0996:                if (clazz.equals(paramTypes[paramTypes.length - 1]))
0997:                    return false;
0998:
0999:                return true;
1000:            }
1001:
1002:            public static void logMethodCall(Object object, String methodName,
1003:                    Object[] arguments) {
1004:                String className = getClassName(object);
1005:                String logname = "methodCalls." + className + "." + methodName;
1006:                Logger objLog = Logger.getLogger(logname);
1007:                if (!objLog.isLoggable(Level.FINER))
1008:                    return;
1009:                StringBuffer msg = new StringBuffer(methodName);
1010:                msg.append("(");
1011:                if (arguments != null) {
1012:                    for (int i = 0; i < arguments.length;) {
1013:                        msg.append(normalizedValue(arguments[i]));
1014:                        if (++i < arguments.length) {
1015:                            msg.append(",");
1016:                        }
1017:                    }
1018:                }
1019:                msg.append(")");
1020:                objLog.logp(Level.FINER, className, msg.toString(),
1021:                        "called from MetaClass.invokeMethod");
1022:            }
1023:
1024:            protected static String normalizedValue(Object argument) {
1025:                String value;
1026:                try {
1027:                    value = argument.toString();
1028:                    if (value.length() > MAX_ARG_LEN) {
1029:                        value = value.substring(0, MAX_ARG_LEN - 2) + "..";
1030:                    }
1031:                    if (argument instanceof  String) {
1032:                        value = "\'" + value + "\'";
1033:                    }
1034:                } catch (Exception e) {
1035:                    value = shortName(argument);
1036:                }
1037:                return value;
1038:            }
1039:
1040:            public static boolean parametersAreCompatible(Class[] arguments,
1041:                    Class[] parameters) {
1042:                if (arguments.length != parameters.length)
1043:                    return false;
1044:                for (int i = 0; i < arguments.length; i++) {
1045:                    if (!isAssignableFrom(parameters[i], arguments[i]))
1046:                        return false;
1047:                }
1048:                return true;
1049:            }
1050:
1051:            protected static String shortName(Object object) {
1052:                if (object == null || object.getClass() == null)
1053:                    return "unknownClass";
1054:                String name = getClassName(object);
1055:                if (name == null)
1056:                    return "unknownClassName"; // *very* defensive...
1057:                int lastDotPos = name.lastIndexOf('.');
1058:                if (lastDotPos < 0 || lastDotPos >= name.length() - 1)
1059:                    return name;
1060:                return name.substring(lastDotPos + 1);
1061:            }
1062:
1063:            public static Class[] wrap(Class[] classes) {
1064:                Class[] wrappedArguments = new Class[classes.length];
1065:                for (int i = 0; i < wrappedArguments.length; i++) {
1066:                    Class c = classes[i];
1067:                    if (c == null)
1068:                        continue;
1069:                    if (c.isPrimitive()) {
1070:                        if (c == Integer.TYPE) {
1071:                            c = Integer.class;
1072:                        } else if (c == Byte.TYPE) {
1073:                            c = Byte.class;
1074:                        } else if (c == Long.TYPE) {
1075:                            c = Long.class;
1076:                        } else if (c == Double.TYPE) {
1077:                            c = Double.class;
1078:                        } else if (c == Float.TYPE) {
1079:                            c = Float.class;
1080:                        }
1081:                    } else if (isSuperclass(c, GString.class)) {
1082:                        c = String.class;
1083:                    }
1084:                    wrappedArguments[i] = c;
1085:                }
1086:                return wrappedArguments;
1087:            }
1088:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.