How to Seamlessly Combine Java and Lua: A Step‑by‑Step Guide

This tutorial explains how to integrate Lua scripts into Java applications and how to call Java code from Lua, covering the LuaJ and LuaJava libraries, Maven dependencies, code examples for executing Lua, passing functions, dynamic extensions, and automatic script upgrades.

Architect
Architect
Architect
How to Seamlessly Combine Java and Lua: A Step‑by‑Step Guide

Lua is a lightweight scripting language often used in games and embedded systems. Because it lacks multithreading and native GUI support, developers sometimes combine it with Java to compensate for each language's shortcomings.

1. Using Lua in Java

1.1 Using LuaJ library

LuaJ is a Java implementation of a Lua interpreter that provides a bridge between Java and Lua via JNI. It consists of three parts: a Lua compiler that generates bytecode, a Lua virtual machine that executes the bytecode, and bridge classes such as LuaValue and LuaFunction that represent Lua values and functions.

Maven dependency:

<dependency>
  <groupId>org.luaj</groupId>
  <artifactId>luaj-jse</artifactId>
  <version>3.0.1</version>
</dependency>

Simple example that creates a global Lua environment and runs a Lua script:

import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;

public class HelloWorld {
    public static void main(String[] args) {
        LuaValue globals = JsePlatform.standardGlobals();
        LuaValue chunk = globals.load("print('Hello, World!')");
        chunk.call();
    }
}

The example obtains a Lua global environment via JsePlatform.standardGlobals(), loads a Lua chunk with globals.load(), and calls it to print "Hello, World!".

When a Lua function needs to be passed as a parameter to a Java method, the LuaFunction class can be used. The following example defines a Lua function that receives two parameters and prints them from Java:

import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;

public class LuaJavaExample {
    public static void main(String[] args) {
        LuaValue globals = JsePlatform.standardGlobals();
        LuaValue luaFunction = LuaValue.valueOf(new TwoParametersFunction());
        invokeJavaMethod(luaFunction);
    }

    public static void invokeJavaMethod(LuaValue luaFunction) {
        luaFunction.call(LuaValue.valueOf("Hello"), LuaValue.valueOf("World"));
    }

    static class TwoParametersFunction extends OneArgFunction {
        @Override
        public LuaValue call(LuaValue arg) {
            String first = arg.checkjstring();
            String second = arg.checkjstring(2);
            System.out.println("First parameter: " + first);
            System.out.println("Second parameter: " + second);
            return LuaValue.NIL;
        }
    }
}

This code demonstrates how Java can invoke a Lua function and handle the parameters.

1.2 Dynamic extension and script auto‑upgrade

Dynamic extension means loading and executing Lua scripts at runtime without stopping or recompiling the Java program. The following example loads an extension.lua script that defines a function addTwoNumbers and calls it from Java:

import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;

public class DynamicExtensionExample {
    public static void main(String[] args) {
        LuaValue globals = JsePlatform.standardGlobals();
        globals.loadfile("extension.lua").call();
        LuaValue luaFunction = globals.get("addTwoNumbers");
        LuaValue result = luaFunction.call(LuaValue.valueOf(10), LuaValue.valueOf(20));
        System.out.println("Result: " + result.toint());
    }
}

Script auto‑upgrade continuously checks for a newer version of a Lua script and loads it when available:

import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;

public class ScriptAutoUpgradeExample {
    public static void main(String[] args) {
        LuaValue globals = JsePlatform.standardGlobals();
        globals.loadfile("script.lua").call();
        while (true) {
            if (hasNewScriptVersion()) {
                globals.loadfile("new_script.lua").call();
            }
            // other program logic
            sleep(1000);
        }
    }

    private static boolean hasNewScriptVersion() {
        // implement detection logic, e.g., compare with remote version
        return false;
    }

    private static void sleep(long ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); }
    }
}

2. Using Java in Lua

2.1 Using LuaJava library

LuaJava is another Java‑Lua bridge that allows Lua scripts to access Java objects and methods. Maven dependency:

<dependency>
  <groupId>com.naef.jnlua</groupId>
  <artifactId>jnlua</artifactId>
  <version>0.9.0</version>
</dependency>

Example that creates a Java object, pushes it to the Lua stack, and calls a method from Lua:

import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;
import com.naef.jnlua.*;

public class HelloWorld {
    public static void main(String[] args) throws Exception {
        LuaState luaState = JNLuaUtil.newState();
        luaState.openLibs();
        luaState.pushJavaObject(new Hello());
        luaState.setGlobal("hello");
        luaState.load("hello:sayHello('World')");
        luaState.call(0, 0);
    }

    public static class Hello {
        public void sayHello(String name) {
            System.out.println("Hello, " + name);
        }
    }
}

The Lua script uses the colon syntax to invoke the Java method sayHello.

2.2 Accessing Java classes from Lua

LuaJava also lets Lua scripts access static Java classes. The following code pushes the Hello class into Lua and calls its static method:

import org.luaj.vm2.*;
import org.luaj.vm2.lib.jse.*;
import com.naef.jnlua.*;

public class HelloWorld {
    public static void main(String[] args) throws Exception {
        LuaState luaState = JNLuaUtil.newState();
        luaState.openLibs();
        luaState.pushJavaClass(Hello.class);
        luaState.setGlobal("Hello");
        luaState.load("Hello.sayHello('World')");
        luaState.call(0, 0);
    }

    public static class Hello {
        public static void sayHello(String name) {
            System.out.println("Hello, " + name);
        }
    }
}

This demonstrates how Lua can invoke static Java methods directly.

3. Summary

The article shows how to use LuaJ to run Lua code inside Java and how to use LuaJava to call Java objects and classes from Lua. Both approaches require adding a bridge library, enable dynamic extensions, and allow automatic script upgrades, thereby increasing flexibility and extensibility of Java applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaLualuajLuaJava
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.