Java + lua

news2024/12/24 2:37:19

 

  • luaj 主要特征

  • luaj 用法示例

  • luaj 实现原理

  • 查找并调用指定的 Java 方法

  • 从 Java 方法获取返回值

  • 将 Lua function 作为参数传递给 Java 方法


在某些业务场景下,我们可能会遇到 lua 中要调用 java 代码情况,当然这个用 JNI 肯定是可以做到的,但是有更加方便的办法:LuaJavaBridge(LuaJava)和 LuaJ。

luaj 主要特征

  • 可以从 Lua 调用 Java Class Static Method

  • 调用 Java 方法时,支持 int/float/boolean/String/Lua function 五种参数类型

  • 可以将 Lua function 作为参数传递给 Java,并让 Java 保存 Lua function 的引用

  • 可以从 Java 调用 Lua 的全局函数,或者调用引用指向的 Lua function

luaj 的功能很简单,但对于集成各种 SDK 来说已经完全满足需求了。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

luaj 用法示例

Java 方法原型:

public static float getNum(float n) {
    return n;
}

lua 调用示例:

-- Java 类的名称
local className = "com/xttblog/Test"
-- 调用 的Java 方法名
local method = 'getNum'
-- 调用 Java 方法需要的参数
local n = 10
local args = {
     n
}
-- 调用 Java 方法
local _, testStaticMethod = luaj.callStaticMethod(className, method, args)

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

luaj 实现原理

luaj 的核心目标有两个:从 Lua 调用 Java, 从 Java 调用 Lua。整理出来就是如下几点

  • 查找并调用指定的 Java 方法

  • 检查调用结果,并从 Java 方法获取返回值

  • 将 Lua function 作为参数传递给 Java 方法

  • 在 Java 方法中调用 Lua function

查找并调用指定的 Java 方法

JNI 提供了 FindClass() 方法用于查找指定的 Class,所以 luaj.callStaticMethod() 的第一个参数就是要调用的 Java Class 的完整类名称(类名称中的“.”要替换为“/”)

找到指定 Class 后,利用 JNI 的 GetStaticMethodID() 方法就可以找到这个类的指定静态方法,前提是要提供静态方法的名称和签名。

所谓签名,就是指Java方法的参数类型和返回类型定义。方法的签名就是类似(Ljava/lang/String;ZZI)V这样的一串描述,通过字节码方式可以查看,如下示例:

关于 Java 方法签名的具体定义,可以参考:JNI Type Signatures

这里要说的是 luaj 可以根据调用参数自动猜测方法签名所以示例中我们并没有写签名。

示例中指定参数:

local args = {n}

luaj 根据这 个参数,会构造出正确的方法签名。

注意:这里要说的是 Lua 里没有办法准确判断一个数值是整数还是浮点数,所以 luaj 在猜测方法签名时,假定所有的数值都是浮点数。所以下面调用会报错:

public static int getNum(int n) {
  return n;
}

-- Java 类的名称
local className = "com/xttblog/Test"
-- 调用 的Java 方法名
local method = 'getNum'
-- 调用 Java 方法需要的参数
local n = 10
local args = {
     n
}
-- 调用 Java 方法
local _, testStaticMethod = luaj.callStaticMethod(className, method, args)

这样是不行的,所以这个时候我们要自己定义签名。

下面给出正确的示例

public static int getNum(int n) {
  return n;
}
-- Java 类的名称
local className = "com/xttblog/Test"
-- 调用 的Java 方法名
local method = 'getNum'
-- 调用 Java 方法需要的参数
local n = 10
local args = {
     n
}
-- 定义签名-- 参数: [I]nteger-- 返回值: [I]nt
local sig = "(I)I"
-- 调用 Java 方法
local _, testStaticMethod = luaj.callStaticMethod(className, method, args,sig)

签名使用“(依次排列的参数类型)返回值类型”的格式,几个例子如下:

签名                                         解释
()V                             参数:无,返回值:无
(I)V                            参数:int,返回值:无
(Ljava/lang/String;)Z           参数:字符串,返回值:布尔值
(IF)Ljava/lang/String;          参数:整数、浮点数,返回值:字符串

这里列出不同类型对应的 Java 签名字符串:

类型名                 类型
I                       整数,或者 Lua function
F                       浮点数
Z                       布尔值
Ljava/lang/String;      字符串
V                       Void 空,仅用于指定一个 Java 方法不返回任何值

Java 方法里接收 Lua function 的参数必须定义为 int 类型

从 Java 方法获取返回值

luaj 会检查调用结果,并从 Java 方法获取返回值。

luaj 调用 Java 方法时,可能会出现各种错误,因此 luaj 提供了一种机制让 Lua 调用代码可以确定 Java 方法是否成功调用。

luaj.callStaticMethod()会返回两个值:

  • 当成功时,第一个值为 true,第二个值是 Java 方法的返回值(如果有)。

  • 当失败时,第一个值为 false,第二个值是错误代码。

下面的代码展示了如何检查返回结果和获得返回值:

public static int AddTwoNumbers(final int number1, final int number2) {
  return number1 + number2;
}

Lua代码

local args = {2, 3}
local sig = "(II)I"
local ok, ret = luaj.callStaticMethod(className, "AddTwoNumbers", args, sig)

if not ok then
print("luaj error:", ret)
else
print("ret:", ret) -- 输出 ret: 5
end

错误代码定义如下:

错误代码                            描述
-1                          不支持的参数类型或返回值类型
-2                          无效的签名
-3                          没有找到指定的方法
-4                          Java 方法执行时抛出了异常
-5                          Java 虚拟机出错
-6                          Java 虚拟机出错

将 Lua function 作为参数传递给 Java 方法

Lua 虚拟机中,Lua function 以值的形式保存。但这个值无法直接给 Java 用,所以 luaj 做了一个 Lua function 引用表。当一个 Lua function 传递给 Java 时,这个 function 对应的值会被存在引用表中,并获得一个唯一的引用 ID (整数)。Java 代码拿到这个引用 ID 后,就可以很方便的调用该 Lua function 了。

所以 Java 方法里接收 Lua function 的参数必须定义为 int 类型。

示例:

public static int getNum(int n) {
  return n;
}

local function callback(result)
     ---方法内容
end
-- Java 类的名称
local className = "com/xttblog/Test"
-- 调用 的Java 方法名
local method = 'getNum'
-- 调用 Java 方法需要的参数
local args = {
     callback
}
-- 定义签名-- 参数: [I]nteger-- 返回值: [I]nt
local sig = "(I)I"
-- 调用 Java 方法
local _, testStaticMethod = luaj.callStaticMethod(className, method, args,sig)

另外,LuaJ 也很好用。只需引入 pom。

然后直接把 lua 代码当做 String 字符串内嵌到 Java 代码中:

String luaStr = "print 'hello,world!'";
Globals globals = JsePlatform.standardGlobals();
LuaValue chunk = globals.load(luaStr);
chunk.call();

也可以创建一个 login.lua 脚本,内容如下:

  --无参函数
   function hello()
      print 'hello'
   end
--带参函数
   function test(str)
      print('data from java is:'..str)
      return 'haha'
   end

然后,Java先载入login.lua脚本并编译,然后再获取指定名称的函数,无参的直接使用call()方法调用,带参的需要通过invoke(LuaValue[])传入参数表:

   String luaPath = "res/lua/login.lua"; //lua脚本文件所在路径
   Globals globals = JsePlatform.standardGlobals();
//加载脚本文件login.lua,并编译
globals.loadfile(luaPath).call();
//获取无参函数hello
LuaValue func = globals.get(LuaValue.valueOf("hello"));
//执行hello方法
func.call();
//获取带参函数test
LuaValue func1 = globals.get(LuaValue.valueOf("test"));
//执行test方法,传入String类型的参数参数
String data = func1.call(LuaValue.valueOf("I'am from Java!")).toString();
   //打印lua函数回传的数据
   Logger.info("data return from lua is:"+data);

运行结果如下:

hello
data from java is:I'am from Java!
八月 07, 2022 5:31:25 下午 com.tw.login.tools.Logger info
信息: lua return data:haha

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/623882.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

三十六、数学知识——组合数(递推法 + 预处理法 + 卢卡斯定理 + 分解质因数求解组合数 + 卡特兰数)

组合数算法主要内容 一、基本思路1、组合数基本概念2、递推法——询问次数多 a b 值较小 模处理(%mod)3、预处理阶乘方法——询问次数较多 a b 值很大 模处理(%mod)4、卢卡斯定理——询问次数较少 (a b 值很大&am…

泰克AFG31051信号发生器产品参数

AFG31000系列任意波函数发生器 概述 验证连接 DUT 后输出波形 InstaView? 技术用在任意波函数发生器上可直接查看连接 DUT 后的实时波形,无需使用示波器或其他设备,节省测试时间并避免因阻抗不匹配导致的实验错误。 高保真度信号与高级模式 在连续模式…

软考高级架构师笔记-6计算机系统性能评价信息系统基础知识

目录 1. 前言 & 考情分析2. 系统配置与性能评价1. 性能指标2. 性能指标3. 阿姆达尔解决方案3.信息系统基础知识1.信息系统的分类2.信息系统的生命周期3.信息系统战略规划3.常见系统介绍1.客户关系管理CRM2.供应链管理SCM3.企业应用集成EAI4.结语1. 前言 & 考情分析 前…

VR全景创业是否真的赚钱?项目真的靠谱吗?

说到创业,也许你心里会觉得这类项目对于技术和资金等要求都是比较高的,先别急着反驳,这是大多数人的心理。我们选择某个创业项目时,都需要从创业成本和盈利利润来做预算,现在告诉你有一个VR全景创业项目,几…

爆火的AIGC到底是一片新蓝海,还是又一次的泡沫?

自ChatGPT发布以来,陷入了AIGC热,无论是大众的讨论、资本的流向还是大厂的加入,AIGC似乎都会是未来几年内最火的新蓝海。 不同于以往的“顶尖科技”泡沫,AIGC是真正可以应用到生活中的,这也是为何它会引发大量“失业论…

操作系统 复习--实训题

一. 简答题(共8题,100分) 1. (简答题) 编程使用fork()函数创建子进程,要求父进程中打印当前进程的 PID 和子进程的 PID,而在子进程中只打印当前进程的 PID。 参考代码: int main() { pid_t child_pid;c…

使用openlayers加载geoserver发布的arcgis瓦片

openlayers版本:6.5 geoserver版本:2.18.0 1. geoserver发布arcgis瓦片 首先去maven上面找最新的gwc-arcgiscache https://mvnrepository.com/artifact/org.geowebcache/gwc-arcgiscache/1.19.1 把这个jar包下载下来放到目录geoserver/WEB-INF/lib下面…

可扩展性与生态应用:Ardor公链AMA回顾

近日,Jelurida团队工程师Francisco Sarrias做客CryptoWallet.com,分享了一些有关Ardor的话题: Ardor是什么? Ardor是一个旨在提高区块链可扩展性的开源平台,这意味着该项目有助于使区块链网络运行更顺畅,用…

10分钟通过云服务器搭建自己的chatGPT镜像服务

通过云服务器搭建自己的chatGPT镜像服务 前提:需要有自己的API KEY 1 购买云服务器 本教程以阿里云的云服务器为例。 阿里云地址:https://www.aliyun.com/?spm5176.28008736.J_3207526240.1.769d3e4dTtNjuI 进入阿里云官网,选择云服务器ECS进…

精选博客系列|VMware如何实现多云基础设施

私有云,公有云,多云,边缘云… 如今,组织的团队、数据和工作负载分布在各种环境中。毫无疑问,这导致了技术上的复杂性增加、安全风险加剧、成本飙升和云战略不连贯的问题。 “39% 的高管难以在(他们的&…

18.4:打印一个字符串的全部排列

打印一个字符串的全部排列 方法一&#xff1a;暴力方法。 //方法一&#xff1a;暴力方法。public static List<String> permutation1(String s) {//str是一个存储字符类型的有序表。ArrayList<Character> str new ArrayList<>();//将字符串中的类型存储在s…

Zookeeper概述

​ ZooKeeper概述 ZooKeeper是什么 zookeeper是一个为分布式应用程序提供的一个分布式开源协调服务框架。是Google的Chubby的一个开源实现&#xff0c;是Hadoop和Hbase的重要组件。主要用于解决分布式集群中应用系统的一致性问题。提供了基于类似Unix系统的目录节点树方式的数…

docker 安装 nsq

一. nsq介绍 nsq介绍 NSQ是一个基于Go语言&#xff0c;由bitly公司开源出来的一款简单易用的消息中间件。 官方和第三方开发了众多客户端功能库&#xff0c;如基于HTTP的nsqd、Go客户端go-nsq、Python客户端pynsq、基于Node.js的JavaScript客户端nsqjs、异步C客户端libnsq、J…

JavaSE-02【类型转换和运算符】

第一章&#xff1a;数据类型转换 Java程序中要求参与计算的数据&#xff0c;必须要保证数据类型的一致&#xff0c; 如果数据类型不一致则发生类型的转换1.1 自动转换 自动转换&#xff1a;将取值范围小的类型自动提升为取回范围大的类型 自动类型转换原理&#xff1a;一个i…

MySql锁知识记录积累(一)

1.关于脏读、幻读和不可重复读 脏读&#xff1a;一个事务A读取到了另一个事务B未提交的数据&#xff0c;叫做脏读 不可重复读&#xff1a;事务A被事务B干扰到了&#xff01;在事务A范围内&#xff0c;两个相同的查询&#xff0c;读取同一条记录&#xff0c;却反返回了不同的结…

运行一个新vue项目踩坑

npm install报错了&#xff0c;主要是因为node版本太高了。去node官网&#xff0c;下载低版本的msi后缀的文件&#xff0c;运行安装。在vs code里&#xff0c;npm下载依赖&#xff0c;并运行即可。 1. 无法cnpm cnpm : 无法加载文件 D:\Program Files\nodejs\node_global\cnpm.…

前端放大镜效果实现

放大镜效果实现 放大图片的需求&#xff0c;一般是在原有的渲染之上&#xff0c;额外添加一个放大框&#xff0c;当鼠标在原图上移动&#xff0c;放大框内就以当前的鼠标为中心&#xff0c;局部放大一定范围&#xff0c;在淘宝商城中是常有的实现。下面将用两种实现。 1、使用d…

是德 DSOX1202A示波器技术参数

KEYSIGHT是德科技 lnfiniiVision 1000 X 系列示波器是具有专业级功能的入门级示波器&#xff0c;配备的联网软件可提供远程控制和数据记录等功能。 它集 6 种仪器的功能于一身&#xff0c;属于是德科技智能测试台必备仪器之一。该系列包含 4 款独具特长的仪器&#xff0c;通过同…

5年功能测试要18K,一问三不知,还反过来怼我,真是醉了····

最近看了很多简历&#xff0c;很多候选人年限不小&#xff0c;但是做的都是一些非常传统的项目&#xff0c;想着也不能通过简历就直接否定一个人&#xff0c;何况现在大环境越来 越难&#xff0c;大家找工作也不容易&#xff0c;于是就打算见一见。 在沟通中发现&#xff0c;由…

坚持#第418天~久违了,二维码系统

公司有了一个新客户&#xff0c;这家客户的货物都是用铁架框装的&#xff0c;铁架框长得都一样&#xff0c;不好区分&#xff0c;只能看标签来识别&#xff0c;而且发货时需要一一核对发货单上的交货单号对应的货物&#xff0c;标签上的发货单号必须要一致才行&#xff0c;导致…