metaclasshelper.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 985 行 · 第 1/3 页
JAVA
985 行
/*
* Copyright 2005 John G. Wilson
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.codehaus.groovy.runtime;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.MetaMethod;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.wrappers.Wrapper;
/**
* @author John Wilson
* @author Jochen Theodorou
*/
public class MetaClassHelper {
public static final Object[] EMPTY_ARRAY = {};
public static Class[] EMPTY_TYPE_ARRAY = {};
protected static final Object[] ARRAY_WITH_NULL = { null };
protected static final Logger log = Logger.getLogger(MetaClassHelper.class.getName());
private static final int MAX_ARG_LEN = 12;
public static boolean accessibleToConstructor(final Class at, final Constructor constructor) {
boolean accessible = false;
if (Modifier.isPublic(constructor.getModifiers())) {
accessible = true;
}
else if (Modifier.isPrivate(constructor.getModifiers())) {
accessible = at.getName().equals(constructor.getName());
}
else if ( Modifier.isProtected(constructor.getModifiers()) ) {
if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() == null ) {
accessible = true;
}
else if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() != null ) {
accessible = false;
}
else if ( at.getPackage() != null && constructor.getDeclaringClass().getPackage() == null ) {
accessible = false;
}
else if ( at.getPackage().equals(constructor.getDeclaringClass().getPackage()) ) {
accessible = true;
}
else {
boolean flag = false;
Class clazz = at;
while ( !flag && clazz != null ) {
if (clazz.equals(constructor.getDeclaringClass()) ) {
flag = true;
break;
}
if (clazz.equals(Object.class) ) {
break;
}
clazz = clazz.getSuperclass();
}
accessible = flag;
}
}
else {
if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() == null ) {
accessible = true;
}
else if ( at.getPackage() == null && constructor.getDeclaringClass().getPackage() != null ) {
accessible = false;
}
else if ( at.getPackage() != null && constructor.getDeclaringClass().getPackage() == null ) {
accessible = false;
}
else if ( at.getPackage().equals(constructor.getDeclaringClass().getPackage()) ) {
accessible = true;
}
}
return accessible;
}
public static Object[] asWrapperArray(Object parameters, Class componentType) {
Object[] ret=null;
if (componentType == boolean.class) {
boolean[] array = (boolean[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Boolean(array[i]);
}
} else if (componentType == char.class) {
char[] array = (char[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Character(array[i]);
}
} else if (componentType == byte.class) {
byte[] array = (byte[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Byte(array[i]);
}
} else if (componentType == int.class) {
int[] array = (int[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Integer(array[i]);
}
} else if (componentType == short.class) {
short[] array = (short[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Short(array[i]);
}
} else if (componentType == long.class) {
long[] array = (long[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Long(array[i]);
}
} else if (componentType == double.class) {
double[] array = (double[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Double(array[i]);
}
} else if (componentType == float.class) {
float[] array = (float[]) parameters;
ret = new Object[array.length];
for (int i=0; i<array.length; i++) {
ret[i] = new Float(array[i]);
}
}
return ret;
}
/**
* @param list
* @param parameterType
*/
public static Object asPrimitiveArray(List list, Class parameterType) {
Class arrayType = parameterType.getComponentType();
Object objArray = Array.newInstance(arrayType, list.size());
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
if (arrayType.isPrimitive()) {
if (obj instanceof Integer) {
Array.setInt(objArray, i, ((Integer) obj).intValue());
}
else if (obj instanceof Double) {
Array.setDouble(objArray, i, ((Double) obj).doubleValue());
}
else if (obj instanceof Boolean) {
Array.setBoolean(objArray, i, ((Boolean) obj).booleanValue());
}
else if (obj instanceof Long) {
Array.setLong(objArray, i, ((Long) obj).longValue());
}
else if (obj instanceof Float) {
Array.setFloat(objArray, i, ((Float) obj).floatValue());
}
else if (obj instanceof Character) {
Array.setChar(objArray, i, ((Character) obj).charValue());
}
else if (obj instanceof Byte) {
Array.setByte(objArray, i, ((Byte) obj).byteValue());
}
else if (obj instanceof Short) {
Array.setShort(objArray, i, ((Short) obj).shortValue());
}
}
else {
Array.set(objArray, i, obj);
}
}
return objArray;
}
protected static Class autoboxType(Class type) {
if (type.isPrimitive()) {
if (type == int.class) {
return Integer.class;
}
else if (type == double.class) {
return Double.class;
}
else if (type == long.class) {
return Long.class;
}
else if (type == boolean.class) {
return Boolean.class;
}
else if (type == float.class) {
return Float.class;
}
else if (type == char.class) {
return Character.class;
}
else if (type == byte.class) {
return Byte.class;
}
else if (type == short.class) {
return Short.class;
}
}
return type;
}
private static Class[] primitives = {
byte.class, Byte.class, short.class, Short.class,
int.class, Integer.class, long.class, Long.class,
BigInteger.class, float.class, Float.class,
double.class, Double.class, BigDecimal.class,
Number.class, Object.class
};
private static int[][] primitiveDistanceTable = {
// byte Byte short Short int Integer long Long BigInteger float Float double Double BigDecimal, Number, Object
/* byte*/{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, },
/*Byte*/{ 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, },
/*short*/{ 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, },
/*Short*/{ 14, 15, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, },
/*int*/{ 14, 15, 12, 13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, },
/*Integer*/{ 14, 15, 12, 13, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, },
/*long*/{ 14, 15, 12, 13, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, },
/*Long*/{ 14, 15, 12, 13, 10, 11, 1, 0, 2, 3, 4, 5, 6, 7, 8, 9, },
/*BigInteger*/{ 14, 15, 12, 13, 10, 11, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, },
/*float*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 0, 1, 2, 3, 4, 5, 6, },
/*Float*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 1, 0, 2, 3, 4, 5, 6, },
/*double*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 0, 1, 2, 3, 4, },
/*Double*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 1, 0, 2, 3, 4, },
/*BigDecimal*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 3, 4, 0, 1, 2, },
/*Numer*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 3, 4, 2, 0, 1, },
/*Object*/{ 14, 15, 12, 13, 10, 11, 8, 9, 7, 5, 6, 3, 4, 2, 1, 0, },
};
private static int getPrimitiveIndex(Class c) {
for (byte i=0; i< primitives.length; i++) {
if (primitives[i] == c) return i;
}
return -1;
}
private static int getPrimitiveDistance(Class from, Class to) {
// we know here that from!=to, so a distance of 0 is never valid
// get primitive type indexes
int fromIndex = getPrimitiveIndex(from);
int toIndex = getPrimitiveIndex(to);
if (fromIndex==-1 || toIndex==-1) return -1;
return primitiveDistanceTable[toIndex][fromIndex];
}
private static int getMaximumInterfaceDistance(Class c, Class interfaceClass) {
if (c==interfaceClass) return 0;
Class[] interfaces = c.getInterfaces();
int max = 0;
for (int i=0; i<interfaces.length; i++) {
int sub = 0;
if (interfaces[i].isAssignableFrom(c)) {
sub = 1+ getMaximumInterfaceDistance(interfaces[i],interfaceClass);
}
max = Math.max(max,sub);
}
return max;
}
public static long calculateParameterDistance(Class[] arguments, Class[] parameters) {
int objectDistance=0, interfaceDistance=0;
for (int i=0; i<arguments.length; i++) {
if (parameters[i]==arguments[i]) continue;
if (parameters[i].isInterface()) {
objectDistance+=primitives.length;
interfaceDistance += getMaximumInterfaceDistance(arguments[i],parameters[i]);
continue;
}
if (arguments[i]!=null) {
int pd = getPrimitiveDistance(parameters[i],arguments[i]);
if (pd!=-1) {
objectDistance += pd;
continue;
}
// add one to dist to be sure interfaces are prefered
objectDistance += primitives.length+1;
Class clazz = autoboxType(arguments[i]);
while (clazz!=null) {
if (clazz==parameters[i]) break;
if (clazz==GString.class && parameters[i]==String.class) {
objectDistance+=2;
break;
}
clazz = clazz.getSuperclass();
objectDistance+=3;
}
} else {
// choose the distance to Object if a parameter is null
// this will mean that Object is prefered over a more
// specific type
// remove one to dist to be sure Object is prefered
objectDistance--;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?