metaclasshelper.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 985 行 · 第 1/3 页
JAVA
985 行
// the vargs argument is missing, so fill it with an empty array
Object[] newArgs = new Object[paramTypes.length];
System.arraycopy(argumentArray,0,newArgs,0,argumentArray.length);
Object vargs = makeArray(null,vargsClass,0);
newArgs[newArgs.length-1] = vargs;
return newArgs;
} else if (argumentArray.length==paramTypes.length) {
// the number of arguments is correct, but if the last argument
// is no array we have to wrap it in a array. if the last argument
// is null, then we don't have to do anything
Object lastArgument = argumentArray[argumentArray.length-1];
if (lastArgument!=null && !lastArgument.getClass().isArray()) {
// no array so wrap it
Object vargs = makeArray(lastArgument,vargsClass,1);
System.arraycopy(argumentArray,argumentArray.length-1,vargs,0,1);
argumentArray[argumentArray.length-1]=vargs;
return argumentArray;
} else {
// we may have to box the arguemnt!
return argumentArray;
}
} else if (argumentArray.length>paramTypes.length) {
// the number of arguments is too big, wrap all exceeding elements
// in an array, but keep the old elements that are no vargs
Object[] newArgs = new Object[paramTypes.length];
// copy arguments that are not a varg
System.arraycopy(argumentArray,0,newArgs,0,paramTypes.length-1);
// create a new array for the vargs and copy them
int numberOfVargs = argumentArray.length-paramTypes.length;
Object vargs = makeCommonArray(argumentArray,paramTypes.length-1,vargsClass);
newArgs[newArgs.length-1] = vargs;
return newArgs;
} else {
throw new GroovyBugError("trying to call a vargs method without enough arguments");
}
}
private static GroovyRuntimeException createExceptionText(String init, MetaMethod method, Object object, Object[] args, Throwable reason, boolean setReason) {
return new GroovyRuntimeException(
init
+ method
+ " on: "
+ object
+ " with arguments: "
+ InvokerHelper.toString(args)
+ " reason: "
+ reason,
setReason?reason:null);
}
public static Object doMethodInvoke(Object object, MetaMethod method, Object[] argumentArray) {
Class[] paramTypes = method.getParameterTypes();
argumentArray = coerceArgumentsToClasses(argumentArray,paramTypes);
try {
return method.invoke(object, argumentArray);
} catch (IllegalArgumentException e) {
//TODO: test if this is ok with new MOP, should be changed!
// we don't want the exception being unwrapped if it is a IllegalArgumentException
// but in the case it is for example a IllegalThreadStateException, we want the unwrapping
// from the runtime
//Note: the reason we want unwrapping sometimes and sometimes not is that the method
// invokation tries to invoke the method with and then reacts with type transformation
// if the invokation failed here. This is ok for IllegalArgumentException, but it is
// possible that a Reflector will be used to execute the call and then an Exception from inside
// the method is not wrapped in a InvocationTargetException and we will end here.
boolean setReason = e.getClass() != IllegalArgumentException.class;
throw createExceptionText("failed to invoke method: ", method, object, argumentArray, e, setReason);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw createExceptionText("failed to invoke method: ", method, object, argumentArray, e, true);
}
}
protected static String getClassName(Object object) {
if (object==null) return null;
return (object instanceof Class) ? ((Class)object).getName() : object.getClass().getName();
}
/**
* Returns a callable object for the given method name on the object.
* The object acts like a Closure in that it can be called, like a closure
* and passed around - though really its a method pointer, not a closure per se.
*/
public static Closure getMethodPointer(Object object, String methodName) {
return new MethodClosure(object, methodName);
}
public static Class[] getParameterTypes(Object methodOrConstructor) {
if (methodOrConstructor instanceof MetaMethod) {
MetaMethod method = (MetaMethod) methodOrConstructor;
return method.getParameterTypes();
}
if (methodOrConstructor instanceof Method) {
Method method = (Method) methodOrConstructor;
return method.getParameterTypes();
}
if (methodOrConstructor instanceof Constructor) {
Constructor constructor = (Constructor) methodOrConstructor;
return constructor.getParameterTypes();
}
throw new IllegalArgumentException("Must be a Method or Constructor");
}
public static boolean isAssignableFrom(Class classToTransformTo, Class classToTransformFrom) {
if (classToTransformFrom==null) return true;
classToTransformTo = autoboxType(classToTransformTo);
classToTransformFrom = autoboxType(classToTransformFrom);
if (classToTransformTo == classToTransformFrom) {
return true;
}
// note: there is not coercion for boolean and char. Range matters, precision doesn't
else if (classToTransformTo == Integer.class) {
if ( classToTransformFrom == Integer.class
|| classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class
|| classToTransformFrom == BigInteger.class)
return true;
}
else if (classToTransformTo == Double.class) {
if ( classToTransformFrom == Double.class
|| classToTransformFrom == Integer.class
|| classToTransformFrom == Long.class
|| classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class
|| classToTransformFrom == Float.class
|| classToTransformFrom == BigDecimal.class
|| classToTransformFrom == BigInteger.class)
return true;
}
else if (classToTransformTo == BigDecimal.class) {
if ( classToTransformFrom == Double.class
|| classToTransformFrom == Integer.class
|| classToTransformFrom == Long.class
|| classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class
|| classToTransformFrom == Float.class
|| classToTransformFrom == BigDecimal.class
|| classToTransformFrom == BigInteger.class)
return true;
}
else if (classToTransformTo == BigInteger.class) {
if ( classToTransformFrom == Integer.class
|| classToTransformFrom == Long.class
|| classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class
|| classToTransformFrom == BigInteger.class)
return true;
}
else if (classToTransformTo == Long.class) {
if ( classToTransformFrom == Long.class
|| classToTransformFrom == Integer.class
|| classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class)
return true;
}
else if (classToTransformTo == Float.class) {
if ( classToTransformFrom == Float.class
|| classToTransformFrom == Integer.class
|| classToTransformFrom == Long.class
|| classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class)
return true;
}
else if (classToTransformTo == Short.class) {
if ( classToTransformFrom == Short.class
|| classToTransformFrom == Byte.class)
return true;
}
else if (classToTransformTo==String.class) {
if ( classToTransformFrom == String.class ||
GString.class.isAssignableFrom(classToTransformFrom)) {
return true;
}
}
return classToTransformTo.isAssignableFrom(classToTransformFrom);
}
public static boolean isGenericSetMethod(MetaMethod method) {
return (method.getName().equals("set"))
&& method.getParameterTypes().length == 2;
}
protected static boolean isSuperclass(Class claszz, Class superclass) {
while (claszz!=null) {
if (claszz==superclass) return true;
claszz = claszz.getSuperclass();
}
return false;
}
public static boolean isValidMethod(Class[] paramTypes, Class[] arguments, boolean includeCoerce) {
if (arguments == null) {
return true;
}
int size = arguments.length;
if ( (size>=paramTypes.length || size==paramTypes.length-1)
&& paramTypes.length>0
&& paramTypes[paramTypes.length-1].isArray())
{
// first check normal number of parameters
for (int i = 0; i < paramTypes.length-1; i++) {
if (isAssignableFrom(paramTypes[i], arguments[i])) continue;
return false;
}
// check varged
Class clazz = paramTypes[paramTypes.length-1].getComponentType();
for (int i=paramTypes.length; i<size; i++) {
if (isAssignableFrom(clazz, arguments[i])) continue;
return false;
}
return true;
} else if (paramTypes.length == size) {
// lets check the parameter types match
for (int i = 0; i < size; i++) {
if (isAssignableFrom(paramTypes[i], arguments[i])) continue;
return false;
}
return true;
} else if (paramTypes.length == 1 && size == 0) {
return true;
}
return false;
}
public static boolean isValidMethod(Object method, Class[] arguments, boolean includeCoerce) {
Class[] paramTypes = getParameterTypes(method);
return isValidMethod(paramTypes, arguments, includeCoerce);
}
public static boolean isVargsMethod(Class[] paramTypes, Object[] arguments) {
if (paramTypes.length==0) return false;
if (!paramTypes[paramTypes.length-1].isArray()) return false;
// -1 because the varg part is optional
if (paramTypes.length-1==arguments.length) return true;
if (paramTypes.length-1>arguments.length) return false;
if (arguments.length>paramTypes.length) return true;
// only case left is arguments.length==paramTypes.length
Object last = arguments[arguments.length-1];
if (last==null) return true;
Class clazz = last.getClass();
if (clazz.equals(paramTypes[paramTypes.length-1])) return false;
return true;
}
public static void logMethodCall(Object object, String methodName, Object[] arguments) {
String className = getClassName(object);
String logname = "methodCalls." + className + "." + methodName;
Logger objLog = Logger.getLogger(logname);
if (! objLog.isLoggable(Level.FINER)) return;
StringBuffer msg = new StringBuffer(methodName);
msg.append("(");
if (arguments != null){
for (int i = 0; i < arguments.length;) {
msg.append(normalizedValue(arguments[i]));
if (++i < arguments.length) { msg.append(","); }
}
}
msg.append(")");
objLog.logp(Level.FINER, className, msg.toString(), "called from MetaClass.invokeMethod");
}
protected static String normalizedValue(Object argument) {
String value;
try {
value = argument.toString();
if (value.length() > MAX_ARG_LEN){
value = value.substring(0,MAX_ARG_LEN-2) + "..";
}
if (argument instanceof String){
value = "\'"+value+"\'";
}
} catch (Exception e) {
value = shortName(argument);
}
return value;
}
public static boolean parametersAreCompatible(Class[] arguments, Class[] parameters) {
if (arguments.length!=parameters.length) return false;
for (int i=0; i<arguments.length; i++) {
if (!isAssignableFrom(parameters[i],arguments[i])) return false;
}
return true;
}
protected static String shortName(Object object) {
if (object == null || object.getClass()==null) return "unknownClass";
String name = getClassName(object);
if (name == null) return "unknownClassName"; // *very* defensive...
int lastDotPos = name.lastIndexOf('.');
if (lastDotPos < 0 || lastDotPos >= name.length()-1) return name;
return name.substring(lastDotPos+1);
}
public static Class[] wrap(Class[] classes) {
Class[] wrappedArguments = new Class[classes.length];
for (int i = 0; i < wrappedArguments.length; i++) {
Class c = classes[i];
if (c==null) continue;
if (c.isPrimitive()) {
if (c==Integer.TYPE) {
c=Integer.class;
} else if (c==Byte.TYPE) {
c=Byte.class;
} else if (c==Long.TYPE) {
c=Long.class;
} else if (c==Double.TYPE) {
c=Double.class;
} else if (c==Float.TYPE) {
c=Float.class;
}
} else if (isSuperclass(c,GString.class)) {
c = String.class;
}
wrappedArguments[i]=c;
}
return wrappedArguments;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?