// ============================================================================
// $Id: InvokeNoArgMethod.java,v 1.9 2006/04/26 03:40:37 davidahall Exp $
// Copyright (c) 2003-2005 David A. Hall
// ============================================================================
// The contents of this file are subject to the Common Development and
// Distribution License (CDDL), Version 1.0 (the License); you may not use this
// file except in compliance with the License. You should have received a copy
// of the the License along with this file: if not, a copy of the License is
// available from Sun Microsystems, Inc.
//
// http://www.sun.com/cddl/cddl.html
//
// From time to time, the license steward (initially Sun Microsystems, Inc.) may
// publish revised and/or new versions of the License. You may not use,
// distribute, or otherwise make this file available under subsequent versions
// of the License.
//
// Alternatively, the contents of this file may be used under the terms of the
// GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
// case the provisions of the LGPL are applicable instead of those above. If you
// wish to allow use of your version of this file only under the terms of the
// LGPL, and not to allow others to use your version of this file under the
// terms of the CDDL, indicate your decision by deleting the provisions above
// and replace them with the notice and other provisions required by the LGPL.
// If you do not delete the provisions above, a recipient may use your version
// of this file under the terms of either the CDDL or the LGPL.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// ============================================================================
package net.sf.jga.fn.property;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import net.sf.jga.fn.BinaryFunctor;
import net.sf.jga.fn.EvaluationException;
import net.sf.jga.fn.UnaryFunctor;
import net.sf.jga.fn.adaptor.ChainBinary;
import net.sf.jga.fn.adaptor.ChainUnary;
/**
* Functor that invokes a no-arg method named at construction and returns the
* result or null if the result is void.
* <p>
* Note that declaring the return type incorrectly can result in
* ClassCastExceptions being thrown when the functor is invoked: the compiler
* cannot check the return type of a reflectively loaded method.
* <p>
* Copyright © 2003-2005 David A. Hall
*
* @author <a href="mailto:davidahall@users.sourceforge.net">David A. Hall</a>
**/
public class InvokeNoArgMethod<T,R> extends UnaryFunctor<T,R> {
static final long serialVersionUID = -2651164047444243205L;
// The name of the method
private String _methName;
// The class on which the method is defined
private Class<T> _objclass;
// The method being called (lazily populated after deserialization)
private transient Method _meth;
/**
* Builds a InvokeMethod for the given method, which takes no arguments.
* @throws IllegalArgumentException if the method name is null or empty
*/
public InvokeNoArgMethod(Class<T> objclass, String methName) {
if (methName == null || methName.length() == 0) {
String msg = "Must supply method name";
throw new IllegalArgumentException(msg);
}
if (objclass == null) {
String msg = "Must supply object class";
throw new IllegalArgumentException(msg);
}
_methName = methName;
_objclass = objclass;
try {
_meth = objclass.getMethod(_methName, new Class[0]);
}
catch (NoSuchMethodException x) {
String msg = "No such method: "+x.getMessage();
IllegalArgumentException iax = new IllegalArgumentException(msg);
iax.initCause(x);
throw iax;
}
}
/**
* Builds a InvokeMethod for the given method, which takes no arguments.
* @throws IllegalArgumentException if the method name is null or empty,
* or if it is not defined for the given class, or if it takes arguments
*/
public InvokeNoArgMethod(Class<T> objClass, Method method) {
if (method == null) {
String msg = "Must supply method";
throw new IllegalArgumentException(msg);
}
if (objClass == null) {
String msg = "Must supply object class";
throw new IllegalArgumentException(msg);
}
if (method.getParameterTypes().length != 0) {
String msg = "Method {0} takes arguments";
Object[] args = { method.getName() };
throw new IllegalArgumentException(MessageFormat.format(msg, args));
}
if (!method.getDeclaringClass().isAssignableFrom(objClass)) {
String msg = "Method {0} not defined for class {1}";
Object[] args = { method.getName(), objClass.getName() };
throw new IllegalArgumentException(MessageFormat.format(msg, args));
}
_objclass = objClass;
_meth = method;
_methName = method.getName();
}
/**
* Returns the name of the property that this functor retrieves.
*/
public String getMethodName() {
return _methName;
}
/**
* Returns the type of the method
*/
public Class<R> getReturnType() {
return (Class<R>) _meth.getReturnType();
}
/**
* Lazy loads the method
*/
public synchronized Method getMethod() throws NoSuchMethodException {
if (_meth == null)
_meth = _objclass.getMethod(_methName, new Class[0]);
return _meth;
}
// Unary Functor interface
/**
* Invokes the method on the given object, and returns the result.
* @return the result of the designated method of the object
* @throws EvaluationException if the argument does not have the designated
* public property, or if it is not of the correct type.
*/
public R fn(T obj) {
try {
// @SuppressWarnings
// There's nothing we can do about this other than warn the users
// to make sure that they don't use an inappropriate return type
return (R) getMethod().invoke(obj, new Object[0]);
}
catch (NoSuchMethodException x) {
String msg = "No method {0} for class {1} that takes no arguments";
Object[] args = new Object[]{_methName, _objclass.getName()};
throw new EvaluationException(MessageFormat.format(msg,args), x);
}
catch (ClassCastException x) {
String msg = "ClassCastException: " +_objclass +"." +_methName +"()";
throw new EvaluationException(msg, x);
}
catch (IllegalAccessException x) {
String msg = _objclass +"." +_methName +" is not accessible";
throw new EvaluationException(msg, x);
}
catch (InvocationTargetException x) {
String xmsg = x.getMessage();
String msg = "InvocationException: " +_objclass +"." +_methName
+"()"+(xmsg != null ? (":"+xmsg) : "");
throw new EvaluationException(msg, x);
}
}
/**
* Calls the Visitor's <code>visit(InvokeMethod)</code> method, if it
* implements the nested Visitor interface.
*/
public void accept(net.sf.jga.fn.Visitor v) {
if (v instanceof InvokeNoArgMethod.Visitor)
((InvokeNoArgMethod.Visitor)v).visit(this);
else
v.visit(this);
}
// Object overrides
public String toString() {
return "InvokeNoArgMethod("+_meth+")";
}
// AcyclicVisitor
/**
* Interface for classes that may interpret a <b>InvokeMethod</b>
* function.
*/
public interface Visitor extends net.sf.jga.fn.Visitor {
public void visit(InvokeNoArgMethod host);
}
}
|