metaclassimpl.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 1,511 行 · 第 1/5 页
JAVA
1,511 行
return constructor;
}
constructor = (Constructor) chooseMethod("<init>", constructors, arguments, true);
if (constructor != null) {
return constructor;
}
return null;
}
public MetaMethod retrieveStaticMethod(String methodName, Class[] arguments) {
MethodKey methodKey = new DefaultMethodKey(theClass, methodName, arguments, false);
MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
if (method == null) {
method = pickStaticMethod(theClass,methodName, arguments);
cacheStaticMethod(methodKey, method);
}
return method;
}
public MetaMethod getMethodWithoutCaching(Class sender, String methodName, Class[] arguments, boolean isCallToSuper) {
MetaMethod method = null;
List methods = getMethods(sender,methodName,isCallToSuper);
if (methods!=null && !methods.isEmpty()) {
method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
}
return method;
}
public Object invokeStaticMethod(Object object, String methodName, Object[] arguments) {
checkInitalised();
if (log.isLoggable(Level.FINER)){
MetaClassHelper.logMethodCall(object, methodName, arguments);
}
Class sender = object.getClass();
if (object instanceof Class) sender = (Class) object;
if (sender!=theClass) {
MetaClass mc = registry.getMetaClass(sender);
return mc.invokeStaticMethod(sender,methodName,arguments);
}
if (sender==Class.class) {
return invokeMethod(object,methodName,arguments);
}
if (arguments==null) arguments = EMPTY_ARGUMENTS;
Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
unwrap(arguments);
// lets try use the cache to find the method
MethodKey methodKey = new DefaultMethodKey(sender, methodName, argClasses, false);
MetaMethod method = (MetaMethod) staticMethodCache.get(methodKey);
if (method == null) {
method = pickStaticMethod(sender, methodName, argClasses);
cacheStaticMethod(methodKey.createCopy(), method);
}
if (method != null) {
return MetaClassHelper.doMethodInvoke(object, method, arguments);
}
throw new MissingMethodException(methodName, sender, arguments, true);
}
private MetaMethod pickStaticMethod(Class sender, String methodName, Class[] arguments) {
MetaMethod method = null;
List methods = getStaticMethods(sender,methodName);
if (!methods.isEmpty()) {
method = (MetaMethod) chooseMethod(methodName, methods, arguments, false);
}
if (method == null && theClass != Class.class) {
MetaClass classMetaClass = registry.getMetaClass(Class.class);
method = classMetaClass.pickMethod(methodName, arguments);
}
if (method == null) {
method = (MetaMethod) chooseMethod(methodName, methods, MetaClassHelper.convertToTypeArray(arguments), true);
}
return method;
}
public Object invokeConstructor(Object[] arguments) {
return invokeConstructor(theClass,arguments,false);
}
public int selectConstructorAndTransformArguments(int numberOfCosntructors, Object[] arguments) {
//TODO: that is just a quick prototype, not the real thing!
if (numberOfCosntructors != constructors.size()) {
throw new IncompatibleClassChangeError("the number of constructors during runtime and compile time for "+
this.theClass.getName()+" do not match. Expected "+numberOfCosntructors+" but got "+constructors.size());
}
if (arguments==null) arguments = EMPTY_ARGUMENTS;
Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
unwrap(arguments);
Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
if (constructor == null) {
constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
}
if (constructor==null) {
throw new GroovyRuntimeException(
"Could not find matching constructor for: "
+ theClass.getName()
+ "("+InvokerHelper.toTypeString(arguments)+")");
}
List l = new ArrayList(constructors);
Comparator comp = new Comparator() {
public int compare(Object arg0, Object arg1) {
Constructor c0 = (Constructor) arg0;
Constructor c1 = (Constructor) arg1;
String descriptor0 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c0.getParameterTypes());
String descriptor1 = BytecodeHelper.getMethodDescriptor(Void.TYPE, c1.getParameterTypes());
return descriptor0.compareTo(descriptor1);
}
};
Collections.sort(l,comp);
int found = -1;
for (int i=0; i<l.size(); i++) {
if (l.get(i)!=constructor) continue;
found = i;
break;
}
// NOTE: must be changed to "1 |" if constructor was vargs
int ret = 0 | (found << 8);
return ret;
}
/**
* checks if the initialisation of the class id complete.
* This method should be called as a form of assert, it is no
* way to test if there is still initialisation work to be done.
* Such logic must be implemented in a different way.
* @throws IllegalStateException if the initialisation is incomplete yet
*/
protected void checkInitalised() {
if (!isInitialized())
throw new IllegalStateException(
"initialize must be called for meta " +
"class of "+ theClass +
"("+this.getClass() + ") " +
"to complete initialisation process " +
"before any invocation or field/property " +
"access can be done");
}
private Object invokeConstructor(Class at, Object[] arguments, boolean setAccessible) {
checkInitalised();
if (arguments==null) arguments = EMPTY_ARGUMENTS;
Class[] argClasses = MetaClassHelper.convertToTypeArray(arguments);
unwrap(arguments);
Constructor constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, false);
if (constructor != null) {
return doConstructorInvoke(at, constructor, arguments, true);
}
constructor = (Constructor) chooseMethod("<init>", constructors, argClasses, true);
if (constructor != null) {
return doConstructorInvoke(at, constructor, arguments, true);
}
if (arguments.length == 1) {
Object firstArgument = arguments[0];
if (firstArgument instanceof Map) {
constructor = (Constructor) chooseMethod("<init>", constructors, MetaClassHelper.EMPTY_TYPE_ARRAY, false);
if (constructor != null) {
Object bean = doConstructorInvoke(at, constructor, MetaClassHelper.EMPTY_ARRAY, true);
setProperties(bean, ((Map) firstArgument));
return bean;
}
}
}
throw new GroovyRuntimeException(
"Could not find matching constructor for: "
+ theClass.getName()
+ "("+InvokerHelper.toTypeString(arguments)+")");
}
/**
* Sets a number of bean properties from the given Map where the keys are
* the String names of properties and the values are the values of the
* properties to set
*/
public void setProperties(Object bean, Map map) {
checkInitalised();
for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
Map.Entry entry = (Map.Entry) iter.next();
String key = entry.getKey().toString();
Object value = entry.getValue();
setProperty(bean, key, value);
}
}
/**
* @return the given property's value on the object
*/
public Object getProperty(Class sender, Object object, String name, boolean useSuper, boolean fromInsideClass) {
checkInitalised();
//----------------------------------------------------------------------
// handling of static
//----------------------------------------------------------------------
boolean isStatic = theClass != Class.class && object instanceof Class;
if (isStatic && object != theClass) {
MetaClass mc = registry.getMetaClass((Class) object);
return mc.getProperty(sender,object,name,useSuper,false);
}
MetaMethod method = null;
Object[] arguments = EMPTY_ARGUMENTS;
//----------------------------------------------------------------------
// getter
//----------------------------------------------------------------------
MetaProperty mp = getMetaProperty(sender,name,useSuper, isStatic);
if (mp != null) {
if (mp instanceof MetaBeanProperty) {
MetaBeanProperty mbp = (MetaBeanProperty) mp;
method = mbp.getGetter();
mp = mbp.getField();
}
}
// check for a category method named like a getter
if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
String getterName = "get"+MetaClassHelper.capitalize(name);
method = getCategoryMethodGetter(sender,getterName,false);
}
//----------------------------------------------------------------------
// field
//----------------------------------------------------------------------
if (method==null && mp!=null) {
return mp.getProperty(object);
}
//----------------------------------------------------------------------
// generic get method
//----------------------------------------------------------------------
// check for a generic get method provided through a category
if (method==null && !useSuper && !isStatic && GroovyCategorySupport.hasCategoryInAnyThread()) {
method = getCategoryMethodGetter(sender,"get",true);
if (method!=null) arguments = new Object[]{name};
}
// the generic method is valid, if available (!=null), if static or
// if it is not static and we do no static access
if (method==null && genericGetMethod != null && !(!genericGetMethod.isStatic() && isStatic)) {
arguments = new Object[]{ name };
method = genericGetMethod;
}
//----------------------------------------------------------------------
// special cases
//----------------------------------------------------------------------
if (method==null) {
/** todo these special cases should be special MetaClasses maybe */
if (theClass != Class.class && object instanceof Class) {
MetaClass mc = registry.getMetaClass(Class.class);
return mc.getProperty(Class.class,object,name,useSuper,false);
} else if (object instanceof Collection) {
return DefaultGroovyMethods.getAt((Collection) object, name);
} else if (object instanceof Object[]) {
return DefaultGroovyMethods.getAt(Arrays.asList((Object[]) object), name);
} else {
MetaMethod addListenerMethod = (MetaMethod) listeners.get(name);
if (addListenerMethod != null) {
//TODO: one day we could try return the previously registered Closure listener for easy removal
return null;
}
}
} else {
//----------------------------------------------------------------------
// executing the getter method
//----------------------------------------------------------------------
return MetaClassHelper.doMethodInvoke(object,method,arguments);
}
//----------------------------------------------------------------------
// error due to missing method/field
//----------------------------------------------------------------------
throw new MissingPropertyException(name, theClass);
}
private MetaMethod getCategoryMethodGetter(Class sender, String name, boolean useLongVersion) {
List possibleGenericMethods = GroovyCategorySupport.getCategoryMethods(sender, name);
if (possibleGenericMethods != null) {
for (Iterator iter = possibleGenericMethods.iterator(); iter.hasNext();) {
MetaMethod mmethod = (MetaMethod) iter.next();
Class[] paramTypes = mmethod.getParameterTypes();
if (useLongVersion) {
if (paramTypes.length==1 && paramTypes[0] == String.class) {
return mmethod;
}
} else {
if (paramTypes.length==0) return mmethod;
}
}
}
return null;
}
private MetaMethod getCategoryMethodSetter(Class sender, String name, boolean useLongVersion) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?