寻找一种从C++调用Java的便捷方法

似乎大多数与 JNI(Java 本机接口)相关的文档或帮助程序库都关注从 Java 调用本机代码。这似乎是它的主要用途,即使它能够更多。

我主要想在相反的方向上工作:通过添加一些Java库来修改现有的(相当大的)可移植C++程序。例如,我想让它通过JDBC调用数据库,或通过JMS调用消息队列系统,或者发送电子邮件,或者调用我自己的Java类,等等。但是对于原始的JNI,这是非常不愉快和容易出错的。

因此,理想情况下,我希望编写C++代码,这些代码可以像C++ / CLI可以调用CLR类一样轻松地调用Java类。像这样:

using namespace java::util::regex; // namespaces mapped

Pattern p = Pattern.compile("[,\\s]+");

array<java::lang::String> result = 
    p.split("one,two, three   four ,  five");

for (int i=0; i < result.length(); i++)
    std::cout << result[i] << std::endl;

这样,我就不必通过传递名称和奇怪的签名字符串来手动执行获取方法ID的工作,并且可以免受由调用方法的未经检查的API引起的编程错误的影响。事实上,它看起来很像等效的Java。

铌。我仍然在谈论使用JNI!作为一项基础技术,它非常适合我的需求。它是“进行中”且高效的。我不想在单独的进程中运行Java并对其进行RPC调用。JNI本身很好。我只是想要一个愉快的界面。

必须有一个代码生成工具来使等效C++类,命名空间,方法等,以与我指定的一组Java类所公开的内容完全匹配。生成的C++类将:

  • 让成员函数接受其参数的类似包装版本,然后执行必要的JNI voodoo来进行调用。
  • 以相同的方式包装返回值,以便我可以以自然的方式链接调用。
  • 维护方法 ID 的每个类静态缓存,以避免每次都查找它们。
  • 完全线程安全,可移植,开源。
  • 每次方法调用后自动检查异常,并生成 std C++异常。
  • 当我以通常的JNI方式编写本机方法时,也可以使用,但我需要调用其他Java代码。
  • 数组应该在基元类型和类之间完全一致地工作。
  • 毫无疑问,当它们需要在本地参考系之外生存时,需要像global这样的东西来包装引用 - 同样,对于所有数组/对象引用,应该同样工作。

这样一个免费的,开源的,可移植的库/工具是否存在,还是我在做梦?

注意:我发现了这个现有的问题,但在这种情况下,OP并不像我那样对完美的要求......

更新:关于SWIG的评论将我带到了上一个问题,这似乎表明它主要是关于相反的方向,因此不会做我想做的事。

重要

  • 这是关于能够编写C++操作Java类和对象的代码,而不是相反(见标题!
  • 我已经知道JNI存在(请参阅问题!但是,手写到 JNI API 的代码是不必要的冗长、重复、容易出错、在编译时不进行类型检查等。如果要缓存方法 ID 和类对象,则更加冗长。我想自动生成C++包装类,为我处理所有这些问题。

更新:我已经开始研究我自己的解决方案:

https://github.com/danielearwicker/cppjvm

如果这已经存在,请让我知道!

铌。如果您正在考虑在自己的项目中使用它,请随意,但请记住,现在代码已经使用了几个小时,到目前为止,我只编写了三个非常不繁琐的测试。


答案 1

是的,有一些现有的工具可以做到这一点 - 为Java类生成C++包装器。这使得在C++中使用Java API更加透明和愉快,并且成本和风险更低。

我使用最多的是 JunC++ion。它成熟,强大且稳定。主要作者非常好,反应非常迅速。不幸的是,它是一种商业产品,而且价格昂贵。

Jace是一个免费的开源工具,带有BSD许可证。自从我上次和杰斯一起玩已经很多年了。看起来仍然有一些积极的发展。(我仍然记得十多年前原作者的USENET帖子,问的问题基本上与你问的问题大致相同。

如果需要支持从 Java 到 C++ 的回调,定义实现 Java 接口C++类会很有帮助。至少 JunC++ion 允许您将此类C++类传递给接受回调的 Java 方法。我最后一次尝试杰斯时,它不支持这个 - 但那是七年前的事了。


答案 2

我是Codemesh语言集成产品(包括JunC ++ion)的主要架构师之一。自1999年以来,我们一直在进行这种集成,并且效果非常好。最大的问题不是JNI部分。JNI很乏味,很难调试,但是一旦你做对了,它基本上就是继续工作。时不时地,你会被JVM或操作系统更新破坏,然后你必须微调你的产品,但总的来说它是稳定的。

最大的问题是类型系统映射以及一般可用性和目标解决方案之间的权衡。例如,您声明您不喜欢 JACE 将所有对象引用视为全局变量这一事实。我们做同样的事情(使用一些逃生舱口),因为事实证明,这是最适合95%客户的行为,即使它损害了性能。如果您要发布API或产品,则必须选择使大多数人工作的默认值。选择本地引用作为默认选项是错误的,因为越来越多的人正在编写多线程应用程序,而人们想要从其他语言中使用的许多Java API本质上是多线程的,带有异步回调等。

我们还发现,您确实希望为人们提供一个基于GUI的代码生成器来创建集成规范。一旦他们指定了它,您就可以使用 CLI 版本将其集成到夜间构建中。

祝您的项目好运。要做对,需要做很多工作。我们花了几年时间在它上面,我们仍然定期让它变得更好。


推荐