大家好,
我正在编写一个应用程序,该应用程序基于旧的fox-pro for MS-DOS系统中旧的.dbf文件中存储的信息进行计算,这些计算生成日记帐分录以用于新的记帐ERP系统;用户应该能够即时添加/删除/修改条目的生成。因此,我的解决方案是使用Nashorn脚本引擎:我在应用程序设置中定义了一个文件夹,然后应用程序扫描该文件夹内的所有.js文件,该文件扩展了生成条目的抽象类(Totalizer)和voila。
一切听起来不错,除了它不起作用B-)
Totalizer抽象类的源代码为:
public abstract class Totalizer {
private List<Expense> expenses;
private List<Employee> distribution;
/**
*
* @return Id of the totalizer.
*/
public abstract String getId();
/**
* @return Descriptive title of the totalizer.
*/
public abstract String getTitle();
/**
* Creates the JournalEntry based upon a single DBF record.
*
* @param record dbf record.
* @return List of journal entries.
* @throws java.lang.Exception if any exception is thrown.
*/
public abstract List<JournalEntry> totalize(
DbfRecord record) throws Exception;
public void setExpenseMapping(List<Expense> expenses) {
this.expenses = expenses;
}
public void setDistribution(List<Employee> distribution) {
this.distribution = distribution;
}
}
然后,我有了脚本文件,因为它们都很相似,所以我要共享其中的一个:
/**
* Vacations expenses entry:
*/
var BenefVacaciones = Java.extend(Totalizer, {
getId : function(){
return "diar.BenefVaca";
},
getTitle : function(){
return "Beneficios: Vacaciones.";
},
totalize : function(record){
//TODO: implement this method.
return null;
}
});
/*
* Creates a new instance of BenefVacaciones.
*/
function createInstance() {
return new BenefVacaciones();
}
然后,“加载”脚本的类是Task的实现,它执行以下操作:
//Loads a script and returns totalizer implementation.
public Totalizer loadScript(File aFile) throws IOException, ScriptException{
//creates the engine.
var engine = new NashornScriptEngineFactory().getScriptEngine();
//reads script from FileReader
try(var reader = new FileReader(aFile)){
var obj = engine.eval(reader);
if(obj instanceof Invocable){//if obj is invocable
var inv = (Invocable)obj;//casts to invocable
var ret = inv.invokeFunction("createInstance");//invoke
if(ret instanceof Totalizer){//if invoked function is Totalizer
return (Totalizer)ret;//return that totalizer
}else if(ret == null){//if invoked function returns null
throw new NullPointerException("return value is null.");
}else{//if returns non-null value but isn't Totalizer
throw new ScriptException("Function createInstance won't return Totalizer");
}
}else if(obj == null){//WATCH: If engine.eval returns null
throw new NullPointerException("engine.eval returns null.");
}else{//If engine.eval returns non-invocable value.
throw new ScriptException("Cannot get invocable object.");
}
}
}
当然,此代码应抛出
ScriptException,ReferenceError:在
中未定义“ Totalizer” 在行...
但是,如果我将以下行添加到.js脚本文件中,这是一件有趣的事:
var Totalizer = Java.type('com.fossc.diar.onfalo.jsapi.Totalizer');
然后,engine.eval返回null,当我希望至少获得一个Invocable对象或任何其他对象的实例时,代码执行将落入Totalizer行,并带有注释“ WATCH:If engine.eval返回null”。 没有异常被抛出,所以我没有任何信息。 我还尝试在引擎声明之后立即将以下行添加到loadScript方法:
engine.put(
"Totalizer",
jdk.dynalink.beans.StaticClass.forClass(Totalizer.class));
但是它返回null。还尝试添加始终返回true的类过滤器,但两者均无效。我一直在寻找解决方案,但是似乎没有任何效果,当我在ANY脚本中使用Java.type()时,engine.eval返回一个空对象而不是一个Invocable实例,甚至测试engine.eval(“ var x = Java.type(\'java.lang.String \');“)返回null。
出于用户界面的原因,我正在从JavaFX Task实现中调用loadScript函数,因此我发现了https://stackoverflow.com/questions/33945507/java-nashorn-classnotfoundexception-java-type之后,并且尝试将currentThread.contextClassLoader设置为Totalizer.class.getClassLoader()
我做错什么了吗?
我正在使用以下软件:
答案 0 :(得分:0)
好吧,这有点令人尴尬,但我发现了错误。
var obj = engine.eval(reader);
在这种情况下总是返回null,只有在我写类似这样的东西时才返回值:
engine.eval("2+2");
错误是引擎本身是Invocable对象。因此,我只需要转换引擎,而不是评估结果:
engine.eval(reader);
var inv = (Invocable)engine;
var ret = inv.invokeFunction("createInstance");
if(ret instanceof Totalizer){
return (Totalizer) ret;
}else if(ret == null){
throw new NullPointerException("createInstance returns null.");
}else{
throw new ScriptException("createInstance dont return Totalizer.");
}
一切正常。当然,在那种情况下,如果我在不使用engine.put或Java.type的情况下执行engine.eval,则会出现ReferenceError,因为脚本端不存在Totalizer,这使我只需要“导入”该类即可。 。但是该脚本的engine.eval应该始终返回null,因此,修复错误后,它就会执行操作:返回null。