reflector.java

来自「Hecl编程语言是一个高层次的脚本语言的Java实现。其用意是要小」· Java 代码 · 共 619 行 · 第 1/2 页

JAVA
619
字号
/* Copyright 2007-2008 David N. Welton - DedaSys LLC - http://www.dedasys.com   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.hecl.java;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.InvocationTargetException;import java.util.Enumeration;import java.util.Hashtable;import java.util.List;import java.util.Vector;import org.hecl.DoubleThing;import org.hecl.HeclException;import org.hecl.IntThing;import org.hecl.ListThing;import org.hecl.LongThing;import org.hecl.ObjectThing;import org.hecl.Thing;/** * The <code>Reflector</code> class maps between Java types and Hecl * types in order to make it possible to call Java methods from Hecl. * * @author <a href="mailto:davidw@dedasys.com">David N. Welton</a> * @version 1.0 */public class Reflector {    private Class forclass;    private Method[] methods;    private Hashtable methodnames = null;    private Hashtable constnames;    private Hashtable fieldnames;    private static Object[] return_value = new Object[1];    /**     * Creates a new <code>Reflector</code> instance.     *     * @param classname a <code>String</code> value describing the full name     * (including package) of a Java class.     * @exception HeclException if an error occurs     */    public Reflector(String classname) throws HeclException {	try {	    forclass = Class.forName(classname);	    methods = forclass.getMethods();	    constnames = new Hashtable();	    fieldnames = new Hashtable(); 	    for (Field f : forclass.getFields()) {		int mod = f.getModifiers();		StringBuffer msg = new StringBuffer("");		String name = f.getName();		fieldnames.put(name.toLowerCase(), f);		if (Modifier.isPublic(mod) && Modifier.isFinal(mod) && Modifier.isStatic(mod)) {		    Class type = f.getType();		    if (type == boolean.class) {			constnames.put(name, IntThing.create(f.getBoolean(forclass)));		    } else if (type == double.class) {			constnames.put(name, DoubleThing.create(f.getDouble(forclass)));		    } else if (type == float.class) {			constnames.put(name, DoubleThing.create(f.getFloat(forclass)));		    } else if (type == int.class) {			constnames.put(name, IntThing.create(f.getInt(forclass)));		    } else if (type == long.class) {			constnames.put(name, LongThing.create(f.getLong(forclass)));		    } else if (type == String.class) {			constnames.put(name, new Thing((String)f.get(forclass)));		    } else {			constnames.put(name, ObjectThing.create(f.get(forclass)));		    }		}	    }	} catch (Exception e) {	    throw new HeclException(e.toString());	}    }    /**     * The <code>fillMethods</code> method is called in a "lazy" way     * to fill in the method hash table.  This makes startup time a     * lot faster - these are only filled in the first time they're     * needed.     *     */    private void fillMethods() {	methodnames = new Hashtable();	/* We could also do getDeclaredMethods and do the	 * "subclassing" some other way.  */	for (Method m : methods) {	    Vector<Method> v = null;	    String name = m.getName().toLowerCase();	    if (methodnames.containsKey(name)) {		v = (Vector)methodnames.get(name);	    } else {		v = new Vector<Method>();	    }	    v.add(m);	    methodnames.put(name, v);	}    }    /**     * The <code>instantiate</code> method is called to create an     * instance of a class (new, in other words).     *     * @param argv a <code>Thing</code> value that is mapped onto Java     * parameters and passed to the appropriate constructor for the     * class.     * @return a <code>Thing</code> value     * @exception HeclException if an error occurs     */    public Thing instantiate(Thing[] argv)        throws HeclException {	Object[] args = new Object[0];	Constructor selected = null;	try {	    Constructor[] constructors = forclass.getConstructors();	    if (constructors == null) {		throw new HeclException(forclass.toString() + " has no constructors!");	    }	    for (Constructor c : constructors) {		Class[] javaparams = c.getParameterTypes();		if(javaparams.length != argv.length) {		    continue;		}		if (mapParams(return_value, javaparams, argv, 0)) {		    args = (Object[])return_value[0];		    selected = c;		    break;		}	    }	    if (selected == null) {		throw new HeclException("Couldn't find a constructor for class:" + forclass.getName());	    }	    return ObjectThing.create(selected.newInstance(args));	} catch (InvocationTargetException e) {	    String msg = "Problem invoking " + forclass.getName() + " constructor " + selected.getName() + " with arguments: ";	    for (Thing t : argv) {		msg += t.toString() + " ";	    }	    msg += " (Translated to:) ";	    for (Object eo : args) {		msg += eo.toString() + " ";	    }	    msg += " " + e.getTargetException().toString();	    throw new HeclException(msg);	} catch (Exception e) {	    e.printStackTrace();	    throw new HeclException("Reflector instantiate error :" + e.toString());	}    }    /**     * The <code>getField</code> method returns the value of an     * instance's field.     *     * @param target an <code>Object</code> value     * @param name a <code>String</code> value     * @return a <code>Thing</code> value     * @exception HeclException if an error occurs     */    public Thing getField(Object target, String name)	throws HeclException {	Thing retval = null;	Field f = (Field)fieldnames.get(name.toLowerCase());	if (f == null) {	    throw new HeclException("No field matches " + name + " for class " + forclass.getName() + " " + fieldnames.toString());	}	try {	    Class type = f.getType();	    retval = javaTypeToHeclType(type, f.get(target));	} catch (Exception e) {	    e.printStackTrace();	    throw new HeclException("Problem fetching field " + name + " : " + e.toString());	}	return retval;    }    /**     * The <code>setField</code> method takes an object, a field name,     * and a new Thing value, and sets the object's field to the value     * of Thing.     *     * @param target an <code>Object</code> value     * @param name a <code>String</code> value     * @param newvalue a <code>Thing</code> value     * @exception HeclException if an error occurs     */    public void setField(Object target, String name, Thing newvalue)	throws HeclException {	Field f = (Field)fieldnames.get(name.toLowerCase());	if (f == null) {	    throw new HeclException("No field matches " + name + " for class " + forclass.getName() +				    " " + fieldnames.toString());	}	try {	    Class type = f.getType();	    if (!heclTypeToJavaType(return_value, type, newvalue)) {		throw new HeclException("no match found for " + type);	    }	    f.set(target, return_value[0]);	} catch (Exception e) {	    e.printStackTrace();	    throw new HeclException("Problem setting field " + name + " to " +				    newvalue.toString() + " : " + e.toString());	}    }    /**     * <code>getConstField</code> fetches a constant field value.     *     * @param name a <code>String</code> value     * @return a <code>Thing</code> value     * @exception HeclException if an error occurs     */    public Thing getConstField(String name)	throws HeclException {	Thing result =  (Thing)constnames.get(name);	if (result == null) {	    throw new HeclException("No field '" + name + "'");	}	return result;    }    /**     * The <code>evaluate</code> method takes a target object to     * operate on, a methodname, and some Hecl values, and attempts to     * find and call a Java method with the supplied values.     *     * @param o an <code>Object</code> value     * @param cmd a <code>String</code> value     * @param argv a <code>Thing</code> value     * @return a <code>Thing</code> value     * @exception HeclException if an error occurs     */    public Thing evaluate(Object o, String cmd, Thing[] argv)        throws HeclException {	Object[] args = new Object[0];	Method selected = null;	if (methodnames == null) {	    fillMethods();	}	try {	    Vector<Method> v = ((Vector)methodnames.get(cmd.toLowerCase()));	    if (v == null) {		throw new HeclException("Method " + cmd + " not found for class" + forclass.toString());	    }	    Method[] methods = v.toArray(new Method[v.size()]);	    /* Match the signatures with the correct number first. */	    Class[] javaparams = null;	    for (Method m : methods) {		javaparams = m.getParameterTypes();		if(javaparams.length != argv.length - 2) {		    continue;		}		if (mapParams(return_value, javaparams, argv, 2)) {		    args = (Object[])return_value[0];		    selected = m;		    break;		}	    }	    if (selected == null) {		String msg = "No method matched " + cmd + " for class " + forclass.getName() +		    " last javaparams tried: ";		if (javaparams != null) {		    for (Class c : javaparams) {			msg += c.getSimpleName() + " ";		    }		}		throw new HeclException(msg);	    }	    Object retval = selected.invoke(o, args);	    return mapRetval(selected, retval);	} catch (InvocationTargetException e) {	    String msg = "Problem invoking " + forclass.getName() + " " + cmd + "/" +

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?