/** Invoke specified method as from outside java code, using the declaring interpreter and current namespace. The call stack will indicate that the method is being invoked from outside of bsh in native java code. Note: you must still wrap/unwrap args/return values using Primitive/Primitive.unwrap() for use outside of BeanShell. @see bsh.Primitive */ public Object invokeMethod( String name, Object [] args ) throws EvalError { // null callstack, one will be created for us return invokeMethod( name, args, null/*declaringInterpreter*/, null, null, false/*declaredOnly*/ ); }
/** getThis() is a factory for bsh.This type references. The capabilities of ".this" references in bsh are version dependent up until jdk1.3. The version dependence was to support different default interface implementations. i.e. different sets of listener interfaces which scripted objects were capable of implementing. In jdk1.3 the reflection proxy mechanism was introduced which allowed us to implement arbitrary interfaces. This is fantastic. A This object is a thin layer over a namespace, comprising a bsh object context. We create it here only if needed for the namespace. Note: this method could be considered slow because of the way it dynamically factories objects. However I've also done tests where I hard-code the factory to return JThis and see no change in the rough test suite time. This references are also cached in NameSpace. */ static This getThis( NameSpace namespace, Interpreter declaringInterpreter ) { return new This( namespace, declaringInterpreter ); }
/** Get dynamic proxy for interface, caching those it creates. */ public Object getInterface( Class clas ) { return getInterface( new Class[] { clas } ); }
/** Shared system object visible under bsh.system */ public static void setShutdownOnExit(final boolean value) { try { SYSTEM_OBJECT.getNameSpace().setVariable("shutdownOnExit", Boolean.valueOf(value), false); } catch (final UtilEvalError utilEvalError) { throw new IllegalStateException(utilEvalError); } }
InvocationTargetException { if ( object instanceof This && !This.isExposedThisMethod(methodName) ) return ((This)object).invokeMethod( methodName, args, interpreter, callstack, callerInfo, false/*delcaredOnly*/);
This.this.toString() + "\nimplements:" ); for(int i=0; i<ints.length; i++) sb.append( " "+ ints[i].getName() invokeMethod( methodName, Primitive.wrap(args, paramTypes) ) );
This instanceThis = initClassInstanceThis(instance, className); NameSpace instanceNameSpace = instanceThis.getNameSpace(); clas = clas.getSuperclass(); parentNames.forEach(name -> initClassInstanceThis(instance, name));
This.this.toString(), ": ", ee ); throw ee;
private Object constructObject(Class<?> type, Object[] args, CallStack callstack, Interpreter interpreter ) throws EvalError { final boolean isGeneratedClass = Reflect.isGeneratedClass(type); if (isGeneratedClass) { This.registerConstructorContext(callstack, interpreter); } finally { if (isGeneratedClass) { This.registerConstructorContext(null, null); // clean up, prevent memory leak NameSpace instanceNameSpace = ths.getNameSpace();
thisReference = This.getThis( this, declaringInterpreter );
public static void setShutdownOnExit(final boolean value) { try { SYSTEM_OBJECT.getNameSpace().setVariable("shutdownOnExit", Boolean.valueOf(value), false); } catch (final UtilEvalError utilEvalError) { throw new IllegalStateException(utilEvalError); } }
/** * Invoke method on arbitrary object instance. * invocation may be static (through the object instance) or dynamic. * Object may be a bsh scripted object (bsh.This type). * * @return the result of the method call */ public static Object invokeObjectMethod(Object object, String methodName, Object[] args, BshEvaluatingVisitor visitor, SimpleNode callerInfo) throws ReflectError, EvalError, InvocationTargetException { // Bsh scripted object if (object instanceof This && !This.isExposedThisMethod(methodName)) { return ((This) object).invokeMethod(methodName, args, visitor.getInterpreter(), visitor.getCallstack(), callerInfo, false/*delcaredOnly*/); } // Plain Java object, find the java method try { BshClassManager bcm = visitor.getInterpreter() == null ? null : visitor.getInterpreter().getClassManager(); Class clas = object.getClass(); Method method = resolveExpectedJavaMethod(bcm, clas, object, methodName, args, false); return invokeMethod(method, object, args); } catch (UtilEvalError e) { throw e.toEvalError(callerInfo, visitor.getCallstack()); } }
This.this.toString() + "\nimplements:" ); for(int i=0; i<ints.length; i++) sb.append( " "+ ints[i].getName() invokeMethod( methodName, Primitive.wrap(args, paramTypes) ) );
+ This.this.toString() + ": "+ ee ); throw ee;
/** A This object is a thin layer over a namespace, comprising a bsh object * context. It handles things like the interface types the bsh object * supports and aspects of method invocation on it. * <p> * The declaringInterpreter is here to support callbacks from Java through * generated proxies. The scripted object "remembers" who created it for * things like printing messages and other per-interpreter phenomenon when * called externally from Java. * @param declaringInterpreter the declaring interpreter * @return the this Note: we need a singleton here so that things like 'this * == this' work (and probably a good idea for speed). Caching a * single instance here seems technically incorrect, considering the * declaringInterpreter could be different under some circumstances. * (Case: a child interpreter running a source() / eval() command). * However the effect is just that the main interpreter that * executes your script should be the one involved in call-backs * from Java. I do not know if there are corner cases where a child * interpreter would be the first to use a This reference in a * namespace or if that would even cause any problems if it did... * We could do some experiments to find out... and if necessary we * could cache on a per interpreter basis if we had weak * references... We might also look at skipping over child * interpreters and going to the parent for the declaring * interpreter, so we'd be sure to get the top interpreter. */ public This getThis(final Interpreter declaringInterpreter) { if (this.thisReference == null) this.thisReference = This.getThis(this, declaringInterpreter); return this.thisReference; }
/** Invoke specified method as from outside java code, using the declaring interpreter and current namespace. The call stack will indicate that the method is being invoked from outside of bsh in native java code. Note: you must still wrap/unwrap args/return values using Primitive/Primitive.unwrap() for use outside of BeanShell. @see bsh.Primitive */ public Object invokeMethod( String name, Object [] args ) throws EvalError { // null callstack, one will be created for us return invokeMethod( name, args, null/*declaringInterpreter*/, null, null, false/*declaredOnly*/ ); }
/** Delegate method to return enum values array. * @return array of enum values */ public Object[] enumValues() { return Reflect.getEnumConstants(getNameSpace().classStatic); }
/** Get dynamic proxy for interface, caching those it creates. */ public Object getInterface( Class clas ) { return getInterface( new Class[] { clas } ); }
/** This is the invocation handler for the dynamic proxy. <p> Notes: Inner class for the invocation handler seems to shield this unavailable interface from JDK1.2 VM... I don't understand this. JThis works just fine even if those classes aren't there (doesn't it?) This class shouldn't be loaded if an XThis isn't instantiated in NameSpace.java, should it? */ class Handler implements InvocationHandler, java.io.Serializable { public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { try { return invokeImpl( proxy, method, args ); } catch ( TargetError te ) { // Unwrap target exception. If the interface declares that // it throws the ex it will be delivered. If not it will be // wrapped in an UndeclaredThrowable // This isn't simple because unwrapping this loses all context info. // So rewrap is better than unwrap. - fschmidt Throwable t = te.getTarget(); Class<? extends Throwable> c = t.getClass(); String msg = t.getMessage(); try {
/** Pull provider for class static This. * Called from <clinit> to initialize class BSHSTATIC. * @param uuid the class unique id. * @return This from static namespace. */ public static This pullBshStatic(String uuid) { if (contextStore.containsKey(uuid)) return contextStore.remove(uuid).getThis(null); else // we lost the context, provide empty // container for static final field return This.getThis(null, null); }