blob: e16e900854b566111982841fb3c052f0310d4aab [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* 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.*;
import org.codehaus.groovy.runtime.wrappers.PojoWrapper;
/**
* A helper class to invoke methods or extract properties on arbitrary Java objects dynamically
*
* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
* @version $Revision$
*/
public class Invoker {
protected static final Object[] EMPTY_ARGUMENTS = {
};
protected static final Class[] EMPTY_TYPES = {
};
public MetaClassRegistry getMetaRegistry() {
return metaRegistry;
}
private final MetaClassRegistry metaRegistry = GroovySystem.getMetaClassRegistry();
public MetaClass getMetaClass(Object object) {
return metaRegistry.getMetaClass(object.getClass());
}
/**
* Invokes the given method on the object.
*/
public Object invokeMethod(Object object, String methodName, Object arguments) {
/*
System
.out
.println(
"Invoker - Invoking method on object: "
+ object
+ " method: "
+ methodName
+ " arguments: "
+ InvokerHelper.toString(arguments));
*/
if (object == null) {
object = NullObject.getNullObject();
//throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
}
// if the object is a Class, call a static method from that class
if (object instanceof Class) {
Class theClass = (Class) object;
MetaClass metaClass = metaRegistry.getMetaClass(theClass);
return metaClass.invokeStaticMethod(object, methodName, asArray(arguments));
}
else // it's an instance
{
// if it's not an object implementing GroovyObject (thus not builder, nor a closure)
if (!(object instanceof GroovyObject)) {
return invokePojoMethod(object, methodName, arguments);
}
// it's an object implementing GroovyObject
else {
return invokePogoMethod(object, methodName, arguments);
}
}
}
private Object invokePojoMethod(Object object, String methodName, Object arguments) {
Class theClass = object.getClass();
MetaClass metaClass = metaRegistry.getMetaClass(theClass);
return metaClass.invokeMethod(object, methodName, asArray(arguments));
}
private Object invokePogoMethod(Object object, String methodName, Object arguments) {
GroovyObject groovy = (GroovyObject) object;
try {
// if it's a pure interceptable object (even intercepting toString(), clone(), ...)
if (groovy instanceof GroovyInterceptable) {
return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
}
//else try a statically typed method or a GDK method
return groovy.getMetaClass().invokeMethod(object, methodName, asArray(arguments));
} catch (MissingMethodException e) {
if (e.getMethod().equals(methodName) && object.getClass() == e.getType()) {
// in case there's nothing else, invoke the object's own invokeMethod()
return groovy.invokeMethod(methodName, asUnwrappedArray(arguments));
}
throw e;
}
}
public Object invokeSuperMethod(Object object, String methodName, Object arguments) {
if (object == null) {
throw new NullPointerException("Cannot invoke method " + methodName + "() on null object");
}
Class theClass = object.getClass();
MetaClass metaClass = metaRegistry.getMetaClass(theClass.getSuperclass());
return metaClass.invokeMethod(object, methodName, asArray(arguments));
}
public Object invokeStaticMethod(Class type, String method, Object arguments) {
MetaClass metaClass = metaRegistry.getMetaClass(type);
return metaClass.invokeStaticMethod(type, method, asArray(arguments));
}
public Object invokeConstructorOf(Class type, Object arguments) {
MetaClass metaClass = metaRegistry.getMetaClass(type);
return metaClass.invokeConstructor(asArray(arguments));
}
/**
* Converts the given object into an array; if its an array then just
* cast otherwise wrap it in an array
*/
public Object[] asArray(Object arguments) {
if (arguments == null) {
return EMPTY_ARGUMENTS;
}
if (arguments instanceof Object[]) {
return (Object[]) arguments;
}
return new Object[]{arguments};
}
public Object[] asUnwrappedArray(Object arguments) {
Object[] args = asArray(arguments);
for (int i=0; i<args.length; i++) {
if (args[i] instanceof PojoWrapper) {
args[i] = ((PojoWrapper)args[i]).unwrap();
}
}
return args;
}
/**
* Looks up the given property of the given object
*/
public Object getProperty(Object object, String property) {
if (object == null) {
throw new NullPointerException("Cannot get property: " + property + " on null object");
}
if (object instanceof GroovyObject) {
GroovyObject pogo = (GroovyObject) object;
return pogo.getProperty(property);
}
if (object instanceof Class) {
Class c = (Class) object;
return metaRegistry.getMetaClass(c).getProperty(object, property);
}
return metaRegistry.getMetaClass(object.getClass()).getProperty(object, property);
}
/**
* Sets the property on the given object
*/
public void setProperty(Object object, String property, Object newValue) {
if (object == null) {
throw new GroovyRuntimeException("Cannot set property on null object");
}
if (object instanceof GroovyObject) {
GroovyObject pogo = (GroovyObject) object;
pogo.setProperty(property, newValue);
}
else {
if (object instanceof Class)
metaRegistry.getMetaClass((Class) object).setProperty((Class) object, property, newValue);
else
metaRegistry.getMetaClass(object.getClass()).setProperty(object, property, newValue);
}
}
/**
* Looks up the given attribute (field) on the given object
*/
public Object getAttribute(Object object, String attribute) {
if (object == null) {
throw new NullPointerException("Cannot get attribute: " + attribute + " on null object");
/**
} else if (object instanceof GroovyObject) {
GroovyObject pogo = (GroovyObject) object;
return pogo.getAttribute(attribute);
} else if (object instanceof Map) {
Map map = (Map) object;
return map.get(attribute);
*/
}
else {
if (object instanceof Class) {
return metaRegistry.getMetaClass((Class) object).getAttribute(object, attribute);
} else if (object instanceof GroovyObject) {
return ((GroovyObject)object).getMetaClass().getAttribute(object, attribute);
} else {
return metaRegistry.getMetaClass(object.getClass()).getAttribute(object, attribute);
}
}
}
/**
* Sets the given attribute (field) on the given object
*/
public void setAttribute(Object object, String attribute, Object newValue) {
if (object == null) {
throw new GroovyRuntimeException("Cannot set attribute on null object");
/*
} else if (object instanceof GroovyObject) {
GroovyObject pogo = (GroovyObject) object;
pogo.setProperty(attribute, newValue);
} else if (object instanceof Map) {
Map map = (Map) object;
map.put(attribute, newValue);
*/
}
else {
if (object instanceof Class) {
metaRegistry.getMetaClass((Class) object).setAttribute(object, attribute, newValue);
} else if (object instanceof GroovyObject) {
((GroovyObject)object).getMetaClass().setAttribute(object, attribute, newValue);
} else {
metaRegistry.getMetaClass(object.getClass()).setAttribute(object, attribute, newValue);
}
}
}
/**
* Returns the method pointer for the given object name
*/
public Closure getMethodPointer(Object object, String methodName) {
if (object == null) {
throw new NullPointerException("Cannot access method pointer for '" + methodName + "' on null object");
}
return MetaClassHelper.getMethodPointer(object, methodName);
}
public void removeMetaClass(Class clazz) {
metaRegistry.removeMetaClass(clazz);
}
}