In the Java LuaJ library I would like to know how to require or import a lua script of functions in another lua script called by a lua closure through Java.
You can place your Lua libraries as resources in your Java packages. Then on your lua script that requires another lua script, you require
them relative to your package path.
Here's an example:
Here's our import-me.lua
:
-- make our sample module table global
my_imported = {}
function my_imported.printHello()
print "Hello!"
end
return my_imported
Which is then imported in our sample-that-imports.lua
:
require "com.example.import-me"
my_imported.printHello()
Then we run our sample-that-imports.lua
in our SampleMain
Java class:
package com.example;
...
public class SampleMain {
public static void main(String[] args) {
Globals globals = JsePlatform.standardGlobals();
// Again, we load the lua scripts relative to our package path
LuaValue chunk = globals.loadfile("com/example/sample-that-imports.lua");
chunk.call();
// We could even use our imported library here
chunk = globals.load("my_imported.printHello()");
chunk.call();
}
}
Now to answer your other problems,
For example this does not work…
I've noticed on your Java code that you've assumed that calling loadfile()
would automatically run your lua script. Furthermore, you've assumed that loadfile()
is used for loading your lua modules. However, this isn't how it is supposed to be used.
Your loadfile()
should be able to return a LuaValue
that you need to call()
to run the script itself. You could even safely cast it to a LuaClosure
because this is what loadfile()
actually returns.
To fix your Java code above, you can use this,
public static LuaValue runInputStreamLua(InputStream inputStream) throws Exception {
Prototype luaScriptPrototype = LuaC.instance.compile(inputStream, "");
Globals globals = JsePlatform.standardGlobals();
LuaClosure luaClosure = new LuaClosure(luaScriptPrototype, globals);
return luaClosure.call();
}
I will assume in the above code that you are already using require
in the InputStream
(containing a lua script) that you have passed with the above method. If not then, you can do the following changes:
public static LuaValue runInputStreamLua(InputStream inputStream) throws Exception {
Prototype luaScriptPrototype = LuaC.instance.compile(inputStream, "");
Globals globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.load("require 'com.example.import-me';");
chunk.call();
LuaClosure luaClosure = new LuaClosure(luaScriptPrototype, globals);
return luaClosure.call();
}
In the above changes, I am assuming that your lua module (in our example import-me.lua
) automatically creates a global space for itself (in our example, the my_imported
table). If not, you could do this final touch:
...
LuaValue chunk = globals.load("my_imported = require 'com.example.import-me';");
...
You also should reuse your Globals
(returned by JsePlatform.standardGlobals()
) unless you really want to create a new Globals
table every time you call your method. Furthermore, if you really don't need an InputStream
, and simply wants to load the file itself from its file path (or resource path in your Java package path), you can simplify everything into this:
public static LuaValue runLuaFile(Globals globals, String luafile) {
return globals.loadfile(luafile).call();
}
Or to ensure that our lua module is always imported (or has been require
'd) by our lua script,
public static LuaValue runLuaFile(Globals globals, String luafile) {
LuaValue chunk = globals.load("require 'com.example.import-me';");
chunk.call();
chunk = globals.loadfile(luafile);
return chunk.call();
}
Again, you must specify the complete resource path for our lua file. Here's a sample Java snippet using our simplified method above:
Globals globals = JsePlatform.standardGlobals();
runLuaFile(globals, "com/example/sample-that-imports.lua");
I hope this helps!
Edit:
You've mentioned in the comments that you need to import lua modules from InputStream
s. There are 2 ways to achieve that:
- The first one is to load and run the lua modules that you need, like simple lua scripts – and if case that the lua modules that you need are only compatible with lua's
require
mechanism, you'll have a lot of problems to face.
- The second, easiest, and most efficient way is to simply load the module, place it inside the lua table
package.preload
, mapped with a key as its name (to be used by require
).
We'll use the second method above, as this is exactly what lua's require
mechanism really intends. Here's how to implement it using LuaJ:
public static void preloadLuaModule(Globals globals, String modname, InputStream is) {
LuaValue module = globals.load(is, modname, "bt", globals);
globals.get("package").get("preload").set(modname, module);
}
The above utility method pre-loads an InputStream
to be used by require
. Here's an example usage:
Somewhere in the beginning of everything, we initialize stuffs:
...
preloadLuaModule(globals, "sample_module", sampleModuleInputStream);
...
And our sampleModuleInputStream
above is a lua module with the following content:
-- make our sample module table global
sample_module = {}
function sample_module.printHi()
print "Hi!"
end
return sample_module
Then we could simply use require "sample_module"
anywhere we like, be it in a Lua script or in Java using LuaJ:
globals.get("require").call("sample_module");