metaclasshelper.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 985 行 · 第 1/3 页

JAVA
985
字号
                Class clazz = parameters[i];
                if (clazz.isPrimitive()) {
                    objectDistance+=2;
                } else {
                    while (clazz!=Object.class) {
                        clazz = clazz.getSuperclass();
                        objectDistance+=2;
                    }
                }
            }
        }
        long ret = objectDistance;
        ret <<= 32;
        ret |= interfaceDistance;
        return ret;
    }
    
    public static String capitalize(String property) {
        return property.substring(0, 1).toUpperCase() + property.substring(1, property.length());
    }
    
    /**
     * @return the method with 1 parameter which takes the most general type of
     *         object (e.g. Object)
     */
    public static Object chooseEmptyMethodParams(List methods) {
        for (Iterator iter = methods.iterator(); iter.hasNext();) {
            Object method = iter.next();
            Class[] paramTypes = getParameterTypes(method);
            int paramLength = paramTypes.length;
            if (paramLength == 0) {
                return method;
            }
        }
        return null;
    }
    
    /**
     * @return the method with 1 parameter which takes the most general type of
     *         object (e.g. Object) ignoring primitve types
     */
    public static Object chooseMostGeneralMethodWith1NullParam(List methods) {
        // lets look for methods with 1 argument which matches the type of the
        // arguments
        Class closestClass = null;
        Object answer = null;
        
        for (Iterator iter = methods.iterator(); iter.hasNext();) {
            Object method = iter.next();
            Class[] paramTypes = getParameterTypes(method);
            int paramLength = paramTypes.length;
            if (paramLength == 1) {
                Class theType = paramTypes[0];
                if (theType.isPrimitive()) continue;
                if (closestClass == null || isAssignableFrom(theType, closestClass)) {
                    closestClass = theType;
                    answer = method;
                }
            }
        }
        return answer;
    }
    
    /**
     * Coerces a GString instance into String if needed
     *
     * @return the coerced argument
     */
    protected static Object coerceGString(Object argument, Class clazz) {
        if (clazz!=String.class) return argument;
        if (!(argument instanceof GString)) return argument;
        return argument.toString();
    }
    
    protected static Object coerceNumber(Object argument, Class param) {
        if ((Number.class.isAssignableFrom(param) || param.isPrimitive()) && argument instanceof Number) { // Number types
            Object oldArgument = argument;
            boolean wasDouble = false;
            boolean wasFloat = false;
            if (param == Byte.class || param == Byte.TYPE ) {
                argument = new Byte(((Number)argument).byteValue());
            } else if (param == Double.class || param == Double.TYPE) {
                wasDouble = true;
                argument = new Double(((Number)argument).doubleValue());
            } else if (param == Float.class || param == Float.TYPE) {
                wasFloat = true;
                argument = new Float(((Number)argument).floatValue());
            } else if (param == Integer.class || param == Integer.TYPE) {
                argument = new Integer(((Number)argument).intValue());
            } else if (param == Long.class || param == Long.TYPE) {
                argument = new Long(((Number)argument).longValue());
            } else if (param == Short.class || param == Short.TYPE) {
                argument = new Short(((Number)argument).shortValue());
            } else if (param == BigDecimal.class ) {
                argument = new BigDecimal(String.valueOf((Number)argument));
            } else if (param == BigInteger.class) {
                argument = new BigInteger(String.valueOf((Number)argument));
            }
            
            if (oldArgument instanceof BigDecimal) {
                BigDecimal oldbd = (BigDecimal) oldArgument;
                boolean throwException = false;
                if (wasDouble) {
                    Double d = (Double) argument;
                    if (d.isInfinite()) throwException = true;
                } else if (wasFloat) {
                    Float f = (Float) argument;
                    if (f.isInfinite()) throwException = true;
                } else {
                    BigDecimal newbd = new BigDecimal(String.valueOf((Number)argument));
                    throwException = !oldArgument.equals(newbd);
                }
                
                if (throwException) throw new IllegalArgumentException(param+" out of range while converting from BigDecimal");
            }

        }
        return argument;
    }
        
     protected static Object coerceArray(Object argument, Class param) {
         if (!param.isArray()) return argument;
         Class argumentClass = argument.getClass();
         if (!argumentClass.isArray()) return argument;
            
         Class paramComponent = param.getComponentType();
         if (paramComponent.isPrimitive()) {
             if (paramComponent == boolean.class && argumentClass==Boolean[].class) {
                 argument = DefaultTypeTransformation.convertToBooleanArray(argument);
             } else if (paramComponent == byte.class && argumentClass==Byte[].class) {
                 argument = DefaultTypeTransformation.convertToByteArray(argument);
             } else if (paramComponent == char.class && argumentClass==Character[].class) {
                 argument = DefaultTypeTransformation.convertToCharArray(argument);
             } else if (paramComponent == short.class && argumentClass==Short[].class) {
                 argument = DefaultTypeTransformation.convertToShortArray(argument);
             } else if (paramComponent == int.class && argumentClass==Integer[].class) {
                 argument = DefaultTypeTransformation.convertToIntArray(argument);
             } else if (paramComponent == long.class &&
                        (argumentClass == Long[].class || argumentClass  == Integer[].class))
             {
                 argument = DefaultTypeTransformation.convertToLongArray(argument);
             } else if (paramComponent == float.class &&
                        (argumentClass == Float[].class || argumentClass == Integer[].class))
             {
                 argument = DefaultTypeTransformation.convertToFloatArray(argument);
             } else if (paramComponent == double.class &&
                        (argumentClass == Double[].class || argumentClass==Float[].class  
                         || BigDecimal.class.isAssignableFrom(argumentClass)))
             {
                 argument = DefaultTypeTransformation.convertToDoubleArray(argument);
             }
         } else if (paramComponent==String.class && argument instanceof GString[]) {
             GString[] strings = (GString[]) argument;
             String[] ret = new String[strings.length];
             for (int i=0; i<strings.length; i++) {
                 ret[i] = strings[i].toString();
             }
             argument = ret;
         }
         return argument;
    }
    
    /**
     * @return true if a method of the same matching prototype was found in the
     *         list
     */
    public static boolean containsMatchingMethod(List list, MetaMethod method) {
        for (Iterator iter = list.iterator(); iter.hasNext();) {
            MetaMethod aMethod = (MetaMethod) iter.next();
            Class[] params1 = aMethod.getParameterTypes();
            Class[] params2 = method.getParameterTypes();
            if (params1.length == params2.length) {
                boolean matches = true;
                for (int i = 0; i < params1.length; i++) {
                    if (params1[i] != params2[i]) {
                        matches = false;
                        break;
                    }
                }
                if (matches) {
                    return true;
                }
            }
        }
        return false;
    }
    
    /**
     * param instance array to the type array
     * @param args
     */
    public static Class[] convertToTypeArray(Object[] args) {
        if (args == null)
            return null;
        int s = args.length;
        Class[] ans = new Class[s];
        for (int i = 0; i < s; i++) {
            Object o = args[i];
            if (o == null) {
                ans[i] = null;
            } else if (o instanceof Wrapper) {
                ans[i] = ((Wrapper) o).getType();
            } else {
                ans[i] = o.getClass();
            } 
        }
        return ans;
    }
    
    /**
     * @param listenerType
     *            the interface of the listener to proxy
     * @param listenerMethodName
     *            the name of the method in the listener API to call the
     *            closure on
     * @param closure
     *            the closure to invoke on the listenerMethodName method
     *            invocation
     * @return a dynamic proxy which calls the given closure on the given
     *         method name
     */
    public static Object createListenerProxy(Class listenerType, final String listenerMethodName, final Closure closure) {
        InvocationHandler handler = new ClosureListener(listenerMethodName, closure);
        return Proxy.newProxyInstance(listenerType.getClassLoader(), new Class[] { listenerType }, handler);
    }
    
    public static Object doConstructorInvoke(Constructor constructor, Object[] argumentArray) {
        if (log.isLoggable(Level.FINER)){
            logMethodCall(constructor.getDeclaringClass(), constructor.getName(), argumentArray);
        }
        argumentArray = coerceArgumentsToClasses(argumentArray,constructor.getParameterTypes());
        try {
            return constructor.newInstance(argumentArray);
        } catch (InvocationTargetException e) {
            throw new InvokerInvocationException(e);
        } catch (IllegalArgumentException e) {
            throw createExceptionText("failed to invoke constructor: ", constructor, argumentArray, e, false);
        } catch (IllegalAccessException e) {
            throw createExceptionText("could not access constructor: ", constructor, argumentArray, e, false);
        } catch (Exception e) {
            throw createExceptionText("failed to invoke constructor: ", constructor, argumentArray, e, true);
        }
    }
    
    private static GroovyRuntimeException createExceptionText(String init, Constructor constructor, Object[] argumentArray, Throwable e, boolean setReason) {
        throw new GroovyRuntimeException(
                init
                + constructor
                + " with arguments: "
                + InvokerHelper.toString(argumentArray)
                + " reason: "
                + e,
                setReason?e:null);
    }

    public static Object[] coerceArgumentsToClasses(Object[] argumentArray, Class[] paramTypes) {
        // correct argumentArray's length
        if (argumentArray == null) {
            argumentArray = EMPTY_ARRAY;
        } else if (paramTypes.length == 1 && argumentArray.length == 0) {
            if (isVargsMethod(paramTypes,argumentArray))
                argumentArray = new Object[]{Array.newInstance(paramTypes[0].getComponentType(),0)};
            else
                argumentArray = ARRAY_WITH_NULL;
        } else if (isVargsMethod(paramTypes,argumentArray)) {
            argumentArray = fitToVargs(argumentArray, paramTypes);
        }
        
        //correct Type
        for (int i=0; i<argumentArray.length; i++) {
            Object argument = argumentArray[i];
            if (argument==null) continue;
            Class parameterType = paramTypes[i];
            if (parameterType.isInstance(argument)) continue;
            
            argument = coerceGString(argument,parameterType);
            argument = coerceNumber(argument,parameterType);
            argument = coerceArray(argument,parameterType);
            argumentArray[i] = argument;
        }
        return argumentArray;
    }

    private static Object makeCommonArray(Object[] arguments, int offset, Class fallback) {
    	// arguments.leght>0 && !=null
    	Class baseClass = null;
    	for (int i = offset; i < arguments.length; i++) {
			if (arguments[i]==null) continue;
			Class argClass = arguments[i].getClass();
			if (baseClass==null) {
				baseClass = argClass;
			} else {
				for (;baseClass!=Object.class; baseClass=baseClass.getSuperclass()){
					if (baseClass.isAssignableFrom(argClass)) break;
				}
			}
		}
        if (baseClass==null) {
            // all arguments were null
            baseClass = fallback;
        }
    	Object result = makeArray(null,baseClass,arguments.length-offset);
    	System.arraycopy(arguments,offset,result,0,arguments.length-offset);
    	return result;
    }
    
    private static Object makeArray(Object obj, Class secondary, int length) {
    	Class baseClass = secondary;
    	if (obj!=null) {
    		baseClass = obj.getClass();
    	}
    	/*if (GString.class.isAssignableFrom(baseClass)) {
    		baseClass = GString.class;
    	}*/
    	return Array.newInstance(baseClass,length);
    }
    
    /**
     * this method is called when the number of arguments to a method is greater than 1
     * and if the method is a vargs method. This method will then transform the given
     * arguments to make the method callable
     * 
     * @param argumentArray the arguments used to call the method
     * @param paramTypes the types of the paramters the method takes
     */
    private static Object[] fitToVargs(Object[] argumentArray, Class[] paramTypes) {
    	Class vargsClass = autoboxType(paramTypes[paramTypes.length-1].getComponentType());
    	
        if (argumentArray.length == paramTypes.length-1) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?