Skip to content

Commit

Permalink
Merge pull request beanshell#718 from nickl-/reload-typed-variable
Browse files Browse the repository at this point in the history
Reload typed variables
  • Loading branch information
nickl- authored Jan 16, 2023
2 parents 1954cb7 + 9521d58 commit 1b9fa35
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 37 deletions.
4 changes: 2 additions & 2 deletions src/conf/version.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
#
#Project version number - populated by maven
#Project build number - incremented by beanshell-maven-plugin
#Mon Jan 16 13:36:37 SAST 2023
build=4191
#Tue Jan 17 01:30:24 SAST 2023
build=4387
release=${project.version}
23 changes: 21 additions & 2 deletions src/main/java/bsh/BSHFormalParameters.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@

package bsh;

class BSHFormalParameters extends SimpleNode
{
class BSHFormalParameters extends SimpleNode implements BshClassManager.Listener {
private String [] paramNames;
private Modifiers [] paramModifiers;
private boolean listener;
/**
For loose type parameters the paramTypes are null.
*/
Expand Down Expand Up @@ -117,5 +117,24 @@ public Object eval( CallStack callstack, Interpreter interpreter )

return paramTypes;
}

/** Property getter for listener.
* @return boolean return the listener */
public boolean isListener() {
return listener;
}

/** Property setter for listener.
* @param listener the listener to set */
public void setListener(boolean listener) {
this.listener = listener;
}

/** {@inheritDoc} */
@Override
public void classLoaderChanged() {
paramTypes = null;
}

}

30 changes: 6 additions & 24 deletions src/main/java/bsh/BSHMethodDeclaration.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,6 @@ class BSHMethodDeclaration extends SimpleNode
int numThrows = 0;
boolean isVarArgs;
private boolean isScriptedObject;
private transient CallStack callstack;
private transient Interpreter interpreter;

BSHMethodDeclaration(int id) { super(id); }

Expand Down Expand Up @@ -90,25 +88,6 @@ synchronized void insureNodesParsed()
isVarArgs = paramsNode.isVarArgs;
}

/** Used to reevaluate the parameter types on class loader changed.
* @return reevaluated types */
Class<?>[] reevalParamTypes() {
try {
paramsNode.paramTypes = null;
paramsNode.eval(callstack, interpreter);
return paramsNode.paramTypes;
} catch (EvalError e) { return paramsNode.paramTypes; }
}

/** Used to reevaluate the return type on class loader changed.
* @return a reevaluated type */
Class<?> reevalReturnType() {
try {
returnType = evalReturnType(callstack, interpreter);
return returnType;
} catch (EvalError e) { return returnType; }
}

/**
Evaluate the return type node.
@return the type or null indicating loosely typed return
Expand Down Expand Up @@ -146,8 +125,6 @@ BSHReturnType getReturnTypeNode() {
public Object eval( CallStack callstack, Interpreter interpreter )
throws EvalError
{
this.interpreter = interpreter;
this.callstack = callstack;
returnType = evalReturnType( callstack, interpreter );
evalNodes( callstack, interpreter );

Expand All @@ -160,7 +137,12 @@ public Object eval( CallStack callstack, Interpreter interpreter )
// look into this
NameSpace namespace = callstack.top();
BshMethod bshMethod = new BshMethod( this, namespace, modifiers, isScriptedObject );
interpreter.getClassManager().addListener(bshMethod);
if (!namespace.isMethod && !namespace.isClass)
interpreter.getClassManager().addListener(bshMethod);
else if (namespace.isMethod && !paramsNode.isListener()) {
interpreter.getClassManager().addListener(paramsNode);
paramsNode.setListener(true);
}

namespace.setMethod( bshMethod );

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/bsh/BSHPrimitiveType.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@

class BSHPrimitiveType extends SimpleNode
{
public Class type;
public Class<?> type;

BSHPrimitiveType(int id) { super(id); }
public Class getType() { return type; }
public Class<?> getType() { return type; }

@Override
public String toString() {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/bsh/BSHTypedVariableDeclaration.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ public Object eval( CallStack callstack, Interpreter interpreter)
((Primitive) value).numberValue());
namespace.setTypedVariable(
dec.name, type, value, modifiers );
if (!namespace.isMethod)
interpreter.getClassManager().addListener(
namespace.getVariableImpl(dec.name, false));
}
value = namespace.getVariable(dec.name);
} catch ( UtilEvalError e ) {
Expand Down
14 changes: 8 additions & 6 deletions src/main/java/bsh/BshMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ public class BshMethod implements Serializable, Cloneable, BshClassManager.Liste

// Scripted method body
protected BSHBlock methodBody;
private BSHMethodDeclaration methodNode;
// Java Method, for a BshObject that delegates to a real Java method
private Invocable javaMethod;
private Object javaObject;
Expand All @@ -90,7 +89,6 @@ public class BshMethod implements Serializable, Cloneable, BshClassManager.Liste
method.paramsNode.paramTypes, method.paramsNode.getParamModifiers(),
method.blockNode, declaringNameSpace, modifiers, method.isVarArgs );
this.isScriptedObject = isScriptedObject;
this.methodNode = method;
}

BshMethod(
Expand Down Expand Up @@ -572,10 +570,14 @@ public int hashCode() {

/** Reload types if reload is true */
private void reloadTypes() {
if (!reload) return;
reload = false;
creturnType = methodNode.reevalReturnType();
cparamTypes = methodNode.reevalParamTypes();
if (reload) try {
reload = false;
if (Reflect.isGeneratedClass(creturnType))
creturnType = declaringNameSpace.getClass(creturnType.getName());
for (int i = 0; i < cparamTypes.length; i++)
if (Reflect.isGeneratedClass(cparamTypes[i]))
cparamTypes[i] = declaringNameSpace.getClass(cparamTypes[i].getName());
} catch (UtilEvalError e) { /* should not happen on reload */ }
}

/** {@inheritDoc} */
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/bsh/Variable.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
*****************************************************************************/
package bsh;

public class Variable implements java.io.Serializable
import java.io.Serializable;

public class Variable implements Serializable, BshClassManager.Listener
{
public static final int DECLARATION=0, ASSIGNMENT=1;
/** A null type means an untyped variable */
Expand Down Expand Up @@ -167,4 +169,12 @@ public String toString() {
return "Variable: " + StringUtil.variableString(this)
+ ", value:" + value + ", lhs = " + lhs;
}

/** {@inheritDoc} */
@Override
public void classLoaderChanged() {
if (Reflect.isGeneratedClass(type)) try {
type = Reflect.getThisNS(type).getClass(type.getName());
} catch (UtilEvalError e) { /** should not happen on reload */ }
}
}
95 changes: 95 additions & 0 deletions src/test/resources/test-scripts/classreload3.bsh
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,99 @@ a = new A();
assertSame("Returns the same typed instance untyped parameter reloaded", a, objectA(a));
assertNotSame("A and A before is not the same", b4, a.getClass());

// assign local typed variable
A assignTypedVar(A a) {
A b = a;
return b;
}
a = new A();
b4 = a.getClass();
assertSame("Returns the same typed instance typed local variable", a, assignTypedVar(a));
class A {}
a = new A();
assertSame("Returns the same typed instance typed local variable reloaded", a, assignTypedVar(a));
assertNotSame("A and A before is not the same", b4, a.getClass());

// scripted object assign local typed variable
A assignThisTypedVar(A a) {
A b = a;
return this.b;
}
a = new A();
b4 = a.getClass();
assertSame("Returns the same typed instance typed instance variable", a, assignThisTypedVar(a));
class A {}
a = new A();
assertSame("Returns the same typed instance typed instance variable reloaded", a, assignThisTypedVar(a));
assertNotSame("A and A before is not the same", b4, a.getClass());

// scripted object return instance method
A thisMethod(A a) {
A get(A b) {
return b;
}
return this.get(a);
}
a = new A();
b4 = a.getClass();
assertSame("Returns the same typed instance typed instance method", a, thisMethod(a));
class A {}
a = new A();
assertSame("Returns the same typed instance typed instance method reloaded", a, thisMethod(a));
assertNotSame("A and A before is not the same", b4, a.getClass());

// scripted object return instance method assign local typed variable
A thisMethodAssignLocal(A a) {
A getC(A b) {
A c = b;
return c;
}
return this.getC(a);
}
a = new A();
b4 = a.getClass();
assertSame("Returns the same typed instance typed instance method local variable", a, thisMethodAssignLocal(a));
class A {}
a = new A();
assertSame("Returns the same typed instance typed instance method local variable reloaded", a, thisMethodAssignLocal(a));
assertNotSame("A and A before is not the same", b4, a.getClass());

{
// in block scripted object return instance method assign local typed variable
A inBlockThisMethodAssignLocal(A a) {
A getC(A b) {
A c = b;
return c;
}
return this.getC(a);
}
a = new A();
b4 = a.getClass();
assertSame("Returns the same typed instance typed instance method local variable", a, inBlockThisMethodAssignLocal(a));
eval("class A {}");
a = new A();
assertSame("Returns the same typed instance typed instance method local variable reloaded", a, inBlockThisMethodAssignLocal(a));
assertNotSame("A and A before is not the same", b4, a.getClass());
}

// Variable of type
A a = new A();
b4 = a.getClass();
assertSame("Variable type same as class type", A.class, a.getClass());
class A {}
a = new A();
assertSame("Variable type still same as class type", A.class, a.getClass());
assertNotSame("A and A before is not the same", b4, a.getClass());

{
// Variable of type in block
A b = new A();
b4 = b.getClass();
assertSame("Variable type in block same as class type", A.class, b.getClass());
eval("class A {}");
b = new A();
assertSame("Variable type in block still same as class type", A.class, b.getClass());
assertNotSame("A and A before is not the same", b4, b.getClass());
}

complete();

0 comments on commit 1b9fa35

Please sign in to comment.