blob: e1f2b1900e4763971ea3228ce189c4be1ba6911f [file] [log] [blame]
/*
* 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 groovy.lang;
import java.lang.reflect.Method;
import java.util.List;
import java.util.logging.Logger;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.runtime.MetaClassHelper;
/**
* Base class for meta class implementations.
* The meta class is used to invoke methods or to get
* fields/properties. For proper initialization of this class
* it is not enough to only call the constructor, the
* initialize() must be called too. The invoke methods should
* check that initialize() was called. Adding methods is
* valid unless initilise method was called. Therefore
* addNewStaticMethod and addNewInstanceMethod should check that
* that initilise awas not called before.
*
*
* @author John Wilson
*
*/
public abstract class MetaClass {
protected static final Logger log = Logger.getLogger(MetaClass.class.getName());
protected static boolean useReflection = false;
public static final Object NO_METHOD_FOUND = new Object();
protected final Class theClass;
private boolean isGroovyObject;
public static boolean isUseReflection() {
return MetaClass.useReflection;
}
/**
* Allows reflection to be enabled in situations where bytecode generation
* of method invocations causes issues.
*
* @param useReflection
*/
public static void setUseReflection(boolean useReflection) {
MetaClass.useReflection = useReflection;
}
protected MetaClass(final Class theClass) {
this.theClass = theClass;
isGroovyObject = GroovyObject.class.isAssignableFrom(theClass);
}
public boolean isGroovyObject(){
return isGroovyObject;
}
public Object invokeMissingMethod(Object instance, String methodName, Object[] arguments) {
GroovyObject pogo = (GroovyObject) instance;
return pogo.invokeMethod(methodName,arguments);
}
public Object invokeMethod(Object object, String methodName, Object arguments) {
if (arguments == null) {
return invokeMethod(object, methodName, MetaClassHelper.EMPTY_ARRAY);
}
if (arguments instanceof Tuple) {
Tuple tuple = (Tuple) arguments;
return invokeMethod(object, methodName, tuple.toArray());
}
if (arguments instanceof Object[]) {
return invokeMethod(object, methodName, (Object[])arguments);
}
else {
return invokeMethod(object, methodName, new Object[]{arguments});
}
}
public Object invokeMethod(Class sender, Object receiver, String methodName, Object[] arguments, boolean isCallToSuper, boolean fromInsideClass){
return invokeMethod(receiver,methodName,arguments);
}
public Object getProperty(Class sender, Object receiver, String messageName, boolean useSuper, boolean fromInsideClass) {
return getProperty(receiver,messageName);
}
public void setProperty(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
setProperty(receiver,messageName,messageValue);
}
public Object getAttribute(Class sender, Object receiver, String messageName, boolean useSuper) {
return getAttribute(receiver,messageName);
}
public void setAttribute(Class sender, Object receiver, String messageName, Object messageValue, boolean useSuper, boolean fromInsideClass) {
setAttribute(receiver,messageName,messageValue);
}
public abstract Object invokeConstructor(Object[] arguments);
public abstract Object invokeMethod(Object object, String methodName, Object[] arguments);
public abstract Object invokeStaticMethod(Object object, String methodName, Object[] arguments);
public abstract Object getProperty(Object object, String property);
public abstract void setProperty(Object object, String property, Object newValue);
public abstract Object getAttribute(Object object, String attribute);
public abstract void setAttribute(Object object, String attribute, Object newValue);
/**
* adds a new instance method to this meta class. Instance
* methods are able to overwrite the original methods of the
* class. Calling this method should not be done after
* initlise was called.
* @param method the method to be added
*/
public abstract void addNewInstanceMethod(Method method);
/**
* adds a new static method to this meta class. This is only
* possible as long as initilise was not called.
* @param method the method to be added
*/
public abstract void addNewStaticMethod(Method method);
/**
* complete the initlialisation process. After this method
* is called no methods should be added to the meta class.
* Invocation of methods or access to fields/proeprties is
* forbidden unless this method is called. This method
* should contain any initialisation code, taking a longer
* time to complete. An example is the creation of the
* Reflector. It is suggested to synchronize this
* method.
*/
public abstract void initialize();
public abstract List getProperties();
public abstract ClassNode getClassNode();
public abstract List getMetaMethods();
public abstract List getMethods();
/**
* Warning, this method will be removed
* @deprecated use invokeConstructor instead
*/
public Object invokeConstructorAt(Class at, Object[] arguments) {
return invokeConstructor(arguments);
}
/**
* Selects a method by name and argument classes. This method
* does not search for an exact match, it searches for a compatible
* method. For this the method selection mechanism is used as provided
* bye the implementation of this MetaClass. pickMethod may or may
* not used during the method selection process when invoking a method
* thereis no warranty for that.
*
* @returns a matching MetaMethod or null
* @throws GroovyRuntimeException if there is more than one matching method
*/
public abstract MetaMethod pickMethod(String methodName, Class[] arguments);
/**
* Warning, this method will be removed
* @deprecated usw pickMethod instead
*/
protected MetaMethod retrieveMethod(String methodName, Class[] arguments) {
return pickMethod(methodName,arguments);
}
}